1
2 /* ########################################
3 * # CliFM #
4 * # The command line file manager #
5 * ######################################## */
6
7 /* GPL2+ License
8 * Copyright (C) 2016-2021, L. Abramovich <johndoe.arch@outlook.com>
9 * All rights reserved.
10
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 * MA 02110-1301, USA.
25 *
26 */
27
28 #include "helpers.h"
29
30 #include <errno.h>
31 #include <libintl.h>
32 #include <locale.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37 #include <termios.h>
38 #include <unistd.h>
39 #include <readline/readline.h>
40 #include <readline/history.h>
41
42 //#include <signal.h>
43
44 #include "aux.h"
45 #include "checks.h"
46 #include "colors.h"
47 #include "config.h"
48 #include "exec.h"
49 #include "history.h"
50 #include "init.h"
51 #include "jump.h"
52 #include "keybinds.h"
53 #include "listing.h"
54 #include "misc.h"
55 #include "navigation.h"
56 #include "profiles.h"
57 #include "prompt.h"
58 #include "readline.h"
59 #include "strings.h"
60 #include "remotes.h"
61
62 /* Globals */
63
64 struct usrvar_t *usr_var = (struct usrvar_t *)NULL;
65 struct actions_t *usr_actions = (struct actions_t *)NULL;
66 /* Workspaces */
67 struct ws_t *ws = (struct ws_t *)NULL;
68 struct kbinds_t *kbinds = (struct kbinds_t *)NULL;
69 struct jump_t *jump_db = (struct jump_t *)NULL;
70 struct bookmarks_t *bookmarks = (struct bookmarks_t *)NULL;
71 struct fileinfo *file_info = (struct fileinfo *)NULL;
72 struct remote_t *remotes = (struct remote_t *)NULL;
73 struct alias_t *aliases = (struct alias_t *)NULL;
74 struct user_t user;
75 /* Store device and inode number of selected files */
76 struct devino_t *sel_devino = (struct devino_t *)NULL;
77 #ifndef _NO_SUGGESTIONS
78 struct suggestions_t suggestion;
79 #endif
80
81 struct autocmds_t *autocmds = (struct autocmds_t *)NULL;
82 struct opts_t opts;
83
84 /* pmsg holds the current program message type */
85 enum prog_msg pmsg = NOMSG;
86 enum comp_type cur_comp_type = TCMP_NONE;
87 struct param xargs;
88 unsigned short term_cols;
89
90 int curcol = 0,
91 currow = 0,
92 flags;
93
94 struct termios
95 orig_termios,
96 shell_tmodes;
97
98 off_t total_sel_size = 0;
99 pid_t own_pid = 0;
100
101 unsigned short
102 term_cols = 0,
103 term_rows = 0;
104
105 regex_t regex_exp;
106 size_t *ext_colors_len = (size_t *)NULL;
107
108 int
109 auto_open = UNSET,
110 autocd = UNSET,
111 autocmd_set = 0,
112 autojump = UNSET,
113 autols = UNSET,
114 bell = DEF_BELL_STYLE,
115 bg_proc = 0,
116 case_sens_dirjump = UNSET,
117 case_sens_path_comp = UNSET,
118 case_sensitive = UNSET, /* Case sensitive file listing */
119 case_sens_search = UNSET,
120 cd_on_quit = UNSET,
121 check_cap = UNSET,
122 check_ext = UNSET,
123 classify = UNSET,
124 clear_screen = UNSET,
125 cmdhist_flag = 0,
126 colorize = UNSET,
127 columned = UNSET,
128 config_ok = 1,
129 control_d_exits = 0,
130 copy_n_rename = 0,
131 cp_cmd = UNSET,
132 cur_ws = UNSET,
133 dequoted = 0,
134 dir_changed = 0,
135 dirhist_map = UNSET,
136 disk_usage = UNSET,
137 elnpad = UNSET,
138 expand_bookmarks = UNSET,
139 ext_cmd_ok = UNSET,
140 files_counter = UNSET,
141 filter_rev = 0,
142 follow_symlinks = UNSET,
143 fzftab = UNSET,
144 highlight = UNSET,
145 home_ok = 1,
146 #ifndef _NO_ICONS
147 icons = UNSET,
148 #endif
149 int_vars = UNSET,
150 internal_cmd = 0,
151 is_sel = 0,
152 kb_shortcut = 0,
153 kbind_busy = 0,
154 light_mode = UNSET,
155 list_folders_first = UNSET,
156 listing_mode = UNSET,
157 logs_enabled = UNSET,
158 long_view = UNSET,
159 max_name_len = UNSET,
160 mime_match = 0,
161 min_name_trim = UNSET,
162 mv_cmd = UNSET,
163 no_eln = UNSET,
164 no_log = 0,
165 only_dirs = UNSET,
166 open_in_foreground = 0,
167 pager = UNSET,
168 tips = UNSET,
169 print_msg = 0,
170 print_selfiles = UNSET,
171 prompt_offset = UNSET,
172 prompt_style = UNSET,
173 recur_perm_error_flag = 0,
174 restore_last_path = UNSET,
175 rl_last_word_start = 0,
176 rl_nohist = 0,
177 rl_notab = 0,
178 sel_is_last = 0,
179 selfile_ok = 1,
180 share_selbox = UNSET,
181 shell = SHELL_NONE,
182 shell_terminal = 0,
183 show_hidden = UNSET,
184 sort = UNSET,
185 sort_reverse = 0,
186 sort_switch = 0,
187 splash_screen = UNSET,
188 suggestions = UNSET,
189 suggest_filetype_color = UNSET,
190 switch_cscheme = 0,
191 #ifndef _NO_TRASH
192 tr_as_rm = UNSET,
193 trash_ok = 1,
194 #endif
195 unicode = UNSET,
196 warning_prompt = UNSET,
197 welcome_message = UNSET,
198 _xrename = 0,
199 xrename = 0;
200
201 //#ifndef _NO_HIGHLIGHT
202 int wrong_cmd = 0;
203 int wrong_cmd_line = 0;
204 //#endif
205
206 int
207 argc_bk = 0,
208 dirhist_cur_index = 0,
209 exit_code = 0,
210 dirhist_total_index = 0,
211 jump_total_rank = 0,
212 max_dirhist = UNSET,
213 max_files = UNSET,
214 max_hist = UNSET,
215 min_jump_rank = UNSET,
216 max_jump_total_rank = UNSET,
217 max_log = UNSET,
218 max_path = UNSET,
219 max_printselfiles = UNSET,
220 shell_is_interactive = 0,
221 trash_n = 0,
222 *eln_as_file = (int *)0;
223
224 size_t
225 actions_n = 0,
226 aliases_n = 0,
227 args_n = 0,
228 autocmds_n = 0,
229 bm_n = 0,
230 cdpath_n = 0,
231 cschemes_n = 0,
232 current_hist_n = 0,
233 curhistindex = 0,
234 eln_as_file_n = 0,
235 ext_colors_n = 0,
236 files = 0,
237 jump_n = 0,
238 kbinds_n = 0,
239 longest = 0,
240 msgs_n = 0,
241 P_tmpdir_len = 0,
242 path_n = 0,
243 path_progsn = 0,
244 prompt_cmds_n = 0,
245 remotes_n = 0,
246 sel_n = 0,
247 tab_offset = 0,
248 user_home_len = 0,
249 usrvar_n = 0,
250 nwords = 0;
251
252 char
253 div_line_char[NAME_MAX],
254 hostname[HOST_NAME_MAX],
255
256 *actions_file = (char *)NULL,
257 *alt_bm_file = (char *)NULL,
258 *alt_config_dir = (char *)NULL,
259 *alt_config_file = (char *)NULL,
260 *alt_kbinds_file = (char *)NULL,
261 *alt_profile = (char *)NULL,
262 *bm_file = (char *)NULL,
263 *colors_dir = (char *)NULL,
264 *config_dir = (char *)NULL,
265 *config_dir_gral = (char *)NULL,
266 *config_file = (char *)NULL,
267 *cur_color = (char *)NULL,
268 *data_dir = (char *)NULL,
269 *cur_cscheme = (char *)NULL,
270 *dirhist_file = (char *)NULL,
271 *encoded_prompt = (char *)NULL,
272 *file_cmd_path = (char *)NULL,
273 *_filter = (char *)NULL,
274 *fzftab_options = (char *)NULL,
275 *hist_file = (char *)NULL,
276 *jump_suggestion = (char *)NULL,
277 *kbinds_file = (char *)NULL,
278 *last_cmd = (char *)NULL,
279 *log_file = (char *)NULL,
280 *ls_colors_bk = (char *)NULL,
281 *mime_file = (char *)NULL,
282 *msg_log_file = (char *)NULL,
283 *opener = (char *)NULL,
284 *pinned_dir = (char *)NULL,
285 *plugins_dir = (char *)NULL,
286 *profile_file = (char *)NULL,
287 *qc = (char *)NULL,
288 *remotes_file = (char *)NULL,
289 *sel_file = (char *)NULL,
290 *stdin_tmp_dir = (char *)NULL,
291 #ifndef _NO_SUGGESTIONS
292 *suggestion_buf = (char *)NULL,
293 *suggestion_strategy = (char *)NULL,
294 #endif
295 *sys_shell = (char *)NULL,
296 *term = (char *)NULL,
297 // *term_bgcolor = (char *)NULL,
298 *tmp_dir = (char *)NULL,
299 #ifndef _NO_TRASH
300 *trash_dir = (char *)NULL,
301 *trash_files_dir = (char *)NULL,
302 *trash_info_dir = (char *)NULL,
303 #endif
304 *usr_cscheme = (char *)NULL,
305 *user_home = (char *)NULL,
306 *wprompt_str = (char *)NULL,
307
308 **argv_bk = (char **)NULL,
309 **bin_commands = (char **)NULL,
310 **bookmark_names = (char **)NULL,
311 **cdpaths = (char **)NULL,
312 **color_schemes = (char **)NULL,
313 **ext_colors = (char **)NULL,
314 **history = (char **)NULL,
315 **messages = (char **)NULL,
316 **old_pwd = (char **)NULL,
317 **paths = (char **)NULL,
318 **profile_names = (char **)NULL,
319 **prompt_cmds = (char **)NULL,
320 **sel_elements = (char **)NULL;
321
322 /* A list of internal commands, with short and long formats. We use two
323 * more lists of commands: one of commands dealing with file names
324 * (is_internal(), in checks.c), and another one listing commands
325 * taking ELN's as parameters (is_internal_f() in strings.c) */
326 const char *internal_cmds[] = {
327 "?", "help",
328 "ac", "ad",
329 "acd", "autocd",
330 "actions",
331 "alias",
332 "ao", "auto-open",
333 "b", "back",
334 "bb", "bleach",
335 "bh", "fh",
336 "bm", "bookmarks",
337 "br", "bulk",
338 "c", "cp",
339 "cc", "colors",
340 "cd",
341 "cl", "columns",
342 "cmd", "commands",
343 "cs", "colorschemes",
344 "d", "dup",
345 "ds", "desel",
346 "edit",
347 "exp", "export",
348 "ext",
349 "f", "forth",
350 "fc",
351 "ff", "folders-first",
352 "fs",
353 "ft", "filter",
354 "history",
355 "hf", "hidden",
356 "icons",
357 "jump", "je", "jc", "jp", "jo",
358 "kb", "keybinds",
359 "l", "ln", "le",
360 "lm",
361 "log",
362 "m", "mv",
363 "md", "mkdir",
364 "mf",
365 "mm", "mime",
366 "mp", "mountpoints",
367 "msg", "messages",
368 "n", "new",
369 "net",
370 "o", "open", "ow",
371 "opener",
372 "p", "pp", "pr", "prop",
373 "path", "cwd",
374 "paste",
375 "pf", "prof", "profile",
376 "pg", "pager",
377 "pin", "unpin",
378 "quit",
379 "r", "rm",
380 "rf", "refresh",
381 "rl", "reload",
382 "s", "sel",
383 "sb", "selbox",
384 "splash",
385 "st", "sort",
386 "t", "tr", "trash",
387 "te",
388 "tips",
389 "touch",
390 "u", "undel", "untrash",
391 "uc", "unicode",
392 "unlink",
393 "v", "vv",
394 "ver", "version",
395 "ws",
396 "x", "X",
397 NULL};
398
399 /* Just a list of internal commands and fixed parameters for the
400 * auto-suggestions system */
401 const char *param_str[] = {
402 "actions edit",
403 "autocd on",
404 "acd on",
405 "autocd off",
406 "acd off",
407 "autocd status",
408 "acd status",
409 "alias import",
410 "ao on",
411 "auto-open on",
412 "ao off",
413 "auto-open off",
414 "ao status",
415 "auto-open status",
416 "b hist",
417 "b clear",
418 "back hist",
419 "back clear",
420 "bm add",
421 "bm del",
422 "bm edit",
423 "bookmarks add",
424 "bookmarks del",
425 "bookmarks edit",
426 "cs edit",
427 "colorscheme edit",
428 "edit",
429 "edit reset",
430 "ext on",
431 "ext off",
432 "ext status",
433 "f hist",
434 "f clear",
435 "forth hist",
436 "forth clear",
437 "fc on",
438 "filescounter on",
439 "fc off",
440 "filescounter off",
441 "fc status",
442 "filescounter status",
443 "ff on",
444 "folders-first on",
445 "ff off",
446 "folders-first off",
447 "ff status",
448 "folders-first status",
449 "ft unset",
450 "filter unset",
451 "hf on",
452 "hf off",
453 "hf status",
454 "hidden on",
455 "hidden off",
456 "hidden status",
457 "history clear",
458 "history edit",
459 "icons on",
460 "icons off",
461 "kb edit",
462 "keybinds edit",
463 "kb reset",
464 "keybinds reset",
465 "kb readline",
466 "keybinds readline",
467 "l edit",
468 "lm on",
469 "lm off",
470 "log clear",
471 "mf unset",
472 "mm info",
473 "mm edit",
474 "mm import",
475 "mime info",
476 "mime edit",
477 "mime import",
478 "msg clear",
479 "messages clear",
480 "net edit",
481 "net mount",
482 "net unmount",
483 "pg on",
484 "pager on",
485 "pg off",
486 "pager off",
487 "pg status",
488 "pager status",
489 "pf set",
490 "pf add",
491 "pf del",
492 "profile set",
493 "profile add",
494 "profile del",
495 "st none",
496 "st name",
497 "st size",
498 "st atime",
499 "st btime",
500 "st ctime",
501 "st owner",
502 "st group",
503 "st ext",
504 "st inode",
505 "st version",
506 "sort none",
507 "sort name",
508 "sort size",
509 "sort atime",
510 "sort btime",
511 "sort ctime",
512 "sort owner",
513 "sort group",
514 "sort ext",
515 "sort inode",
516 "sort version",
517 "st rev",
518 "sort rev",
519 "t list",
520 "t clear",
521 "t del",
522 "tr list",
523 "tr clear",
524 "tr del",
525 "trash list",
526 "trash clear",
527 "trash del",
528 "u all",
529 "undel all",
530 "untrash all",
531 "uc on",
532 "unicode on",
533 "uc off",
534 "unicode off",
535 "uc status",
536 "unicode status",
537 NULL};
538
539 /* To store all the 39 color variables I use, with 46 bytes each, I need
540 * a total of 1,8Kb. It's not much but it could be less if I'd use
541 * dynamically allocated arrays for them (which, on the other side,
542 * would make the whole thing slower and more tedious) */
543
544 /* Colors */
545 char
546 /* File types */
547 bd_c[MAX_COLOR], /* Block device */
548 ca_c[MAX_COLOR], /* Cap file */
549 cd_c[MAX_COLOR], /* Char device */
550 di_c[MAX_COLOR], /* Directory */
551 ed_c[MAX_COLOR], /* Empty dir */
552 ee_c[MAX_COLOR], /* Empty executable */
553 ef_c[MAX_COLOR], /* Empty reg file */
554 ex_c[MAX_COLOR], /* Executable */
555 fi_c[MAX_COLOR], /* Reg file */
556 ln_c[MAX_COLOR], /* Symlink */
557 mh_c[MAX_COLOR], /* Multi-hardlink file */
558 nd_c[MAX_COLOR], /* No read directory */
559 ne_c[MAX_COLOR], /* No read empty dir */
560 nf_c[MAX_COLOR], /* No read file */
561 no_c[MAX_COLOR], /* Unknown */
562 or_c[MAX_COLOR], /* Broken symlink */
563 ow_c[MAX_COLOR], /* Other writable */
564 pi_c[MAX_COLOR], /* FIFO, pipe */
565 sg_c[MAX_COLOR], /* SGID file */
566 so_c[MAX_COLOR], /* Socket */
567 st_c[MAX_COLOR], /* Sticky (not ow)*/
568 su_c[MAX_COLOR], /* SUID file */
569 tw_c[MAX_COLOR], /* Sticky other writable */
570 uf_c[MAX_COLOR], /* Non-'stat'able file */
571
572 /* Interface */
573 bm_c[MAX_COLOR], /* Bookmarked directory */
574 dc_c[MAX_COLOR], /* Files counter */
575 df_c[MAX_COLOR], /* Default color */
576 dh_c[MAX_COLOR], /* Dirhist index */
577 dl_c[MAX_COLOR], /* Dividing line index */
578 el_c[MAX_COLOR], /* ELN */
579 mi_c[MAX_COLOR], /* Misc indicators */
580 ts_c[MAX_COLOR], /* TAB completion suffix */
581 wc_c[MAX_COLOR], /* Welcome message color */
582 wp_c[MAX_COLOR], /* Warning prompt */
583
584 /* Suggestions */
585 sb_c[MAX_COLOR], /* Auto-suggestions: shell builtins */
586 sc_c[MAX_COLOR], /* Auto-suggestions: external commands */
587 sh_c[MAX_COLOR], /* Auto-suggestions: history */
588 sf_c[MAX_COLOR], /* Auto-suggestions: filenames */
589 sx_c[MAX_COLOR], /* Auto-suggestions: internal commands and params */
590 sp_c[MAX_COLOR], /* Auto-suggestions: suggestions pointer */
591
592 #ifndef _NO_ICONS
593 dir_ico_c[MAX_COLOR], /* Directories icon color */
594 #endif
595
596 /* Syntax highlighting */
597 hb_c[MAX_COLOR], /* Brackets: () [] {} */
598 hc_c[MAX_COLOR], /* Comments */
599 hd_c[MAX_COLOR], /* Paths (slashes) */
600 he_c[MAX_COLOR], /* Expansion operators: * ~ */
601 hn_c[MAX_COLOR], /* Numbers */
602 hp_c[MAX_COLOR], /* Parameters: - */
603 hq_c[MAX_COLOR], /* Quoted strings */
604 hr_c[MAX_COLOR], /* Redirection: > */
605 hs_c[MAX_COLOR], /* Process separators: | & ; */
606 hv_c[MAX_COLOR], /* Variables: $ */
607 hw_c[MAX_COLOR], /* Wrong, non-existent command name */
608
609 /* Colors used in the prompt, so that \001 and \002 needs to
610 * be added. This is why MAX_COLOR + 2 */
611 /* Workspaces */
612 ws1_c[MAX_COLOR + 2],
613 ws2_c[MAX_COLOR + 2],
614 ws3_c[MAX_COLOR + 2],
615 ws4_c[MAX_COLOR + 2],
616 ws5_c[MAX_COLOR + 2],
617 ws6_c[MAX_COLOR + 2],
618 ws7_c[MAX_COLOR + 2],
619 ws8_c[MAX_COLOR + 2],
620
621 em_c[MAX_COLOR + 2], /* Error msg color */
622 li_c[MAX_COLOR + 2], /* Sel indicator color */
623 li_cb[MAX_COLOR], /* Sel indicator color (for the files list) */
624 nm_c[MAX_COLOR + 2], /* Notice msg color */
625 wm_c[MAX_COLOR + 2], /* Warning msg color */
626 si_c[MAX_COLOR + 2], /* stealth indicator color */
627 ti_c[MAX_COLOR + 2], /* Trash indicator color */
628 tx_c[MAX_COLOR + 2]; /* Text color */
629
630 #ifdef LINUX_INOTIFY
631 int inotify_fd, inotify_wd = -1;
632 unsigned int INOTIFY_MASK =
633 IN_CREATE | IN_DELETE | IN_DELETE_SELF | IN_MOVE | IN_MOVE_SELF
634 /*#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
635 | IN_DONT_FOLLOW | IN_EXCL_UNLINK | IN_ONLYDIR | IN_MASK_CREATE;
636 #else */
637 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
638 | IN_DONT_FOLLOW | IN_ONLYDIR
639 #endif /* LINUX >= 2.6.15 */
640 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
641 | IN_EXCL_UNLINK
642 #endif /* LINUX >= 2.6.36 */
643 ;
644 #elif defined(BSD_KQUEUE)
645 int kq, event_fd = -1;
646 struct kevent events_to_monitor[NUM_EVENT_FDS];
647 unsigned int KQUEUE_FFLAGS = NOTE_DELETE | NOTE_EXTEND| NOTE_LINK
648 | NOTE_RENAME | NOTE_REVOKE | NOTE_WRITE;
649 struct timespec timeout;
650 #endif
651 int watch = -1;
652
653 /*
654 static void
655 handle_sigwinch(int c)
656 {
657 UNUSED(c);
658
659 if (kbind_busy)
660 return;
661
662 if (clear_screen)
663 CLEAR;
664
665 keybind_exec_cmd("rf");
666 } */
667
668 /**
669 * #############################
670 * # MAIN #
671 * #############################
672 * */
673
674 int
main(int argc,char * argv[])675 main(int argc, char *argv[])
676 {
677 /* Though this program might perfectly work on other architectures,
678 * I just didn't test anything beyond x86 and ARM */
679 #if !defined(__x86_64__) && !defined(__i386__) && !defined(__ARM_ARCH)
680 fprintf(stderr, _("%s: Unsupported CPU architecture\n"), PROGRAM_NAME);
681 exit(EXIT_FAILURE);
682 #endif
683
684 #if !defined(__linux__) && !defined(__FreeBSD__) \
685 && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__HAIKU__)
686 fprintf(stderr, _("%s: Unsupported operating system\n"), PROGRAM_NAME);
687 exit(EXIT_FAILURE);
688 #endif
689
690 /* Make sure we are running on a supported terminal */
691 check_term();
692
693 /* get_term_bgcolor(STDIN_FILENO, STDOUT_FILENO);
694 printf("\x1b]11;#111111\007"); */
695
696 // signal(SIGWINCH, handle_sigwinch);
697
698 /* Set the default color */
699 /* fputs(DEF_DF_C, stdout);
700 fflush(stdout); */
701
702 /* If running the program locally, that is, not from a path in PATH,
703 * remove the leading "./" to get the correct program invocation
704 * name */
705 if (*argv[0] == '.' && *(argv[0] + 1) == '/')
706 argv[0] += 2;
707
708 /* Use the locale specified by the environment */
709 setlocale(LC_ALL, "");
710
711 unicode = DEF_UNICODE;
712
713 /* Store external arguments to be able to rerun external_arguments()
714 * in case the user edits the config file, in which case the program
715 * must rerun init_config(), get_aliases(), get_prompt_cmds(), and
716 * then external_arguments() */
717 backup_argv(argc, argv);
718
719 /* free_stuff does some cleaning */
720 atexit(free_stuff);
721
722 user = get_user();
723 get_home();
724
725 if (geteuid() == 0)
726 flags |= ROOT_USR;
727
728 /* Running in a graphical environment? */
729 #if __linux__
730 if (getenv("DISPLAY") != NULL && strncmp(getenv("TERM"), "linux", 5) != 0)
731 #else
732 if (getenv("DISPLAY") != NULL)
733 #endif
734 flags |= GUI;
735
736 /* Get paths from PATH environment variable. These paths will be
737 * used later by get_path_programs (for the autocomplete function)
738 * and get_cmd_path() */
739 path_n = get_path_env();
740 cdpath_n = get_cdpath();
741 P_tmpdir_len = strlen(P_tmpdir);
742 init_workspaces();
743
744 /* Set all external arguments flags to uninitialized state */
745 unset_xargs();
746
747 /* Manage external arguments, but only if any: argc == 1 equates to
748 * no argument, since this '1' is just the program invokation name.
749 * External arguments will override initialization values
750 * (init_config) */
751 if (argc > 1)
752 external_arguments(argc, argv);
753 /* external_arguments is executed before init_config because, if
754 * specified (-P option), it sets the value of alt_profile, which
755 * is then checked by init_config */
756
757 check_env_filter();
758 get_data_dir();
759
760 /* Initialize program paths and files, set options from the config
761 * file, if they were not already set via external arguments, and
762 * load sel elements, if any. All these configurations are made
763 * per user basis */
764
765 init_config();
766 check_options();
767 set_sel_file();
768 create_tmp_files();
769 load_actions();
770 get_aliases();
771
772 /* Get the list of available applications in PATH to be used by my
773 * custom TAB-completion function */
774 get_path_programs();
775
776 /* Check third-party programs availability: FZF, udevil, and udisks2 */
777 check_third_party_cmds();
778
779 /* Initialize gettext() for translations */
780 #ifndef _NO_GETTEXT
781 init_gettext();
782 #endif
783
784 /* cschemes_n = get_colorschemes();
785 set_colors(usr_cscheme ? usr_cscheme : "default", 1);
786 free(usr_cscheme);
787 usr_cscheme = (char *)NULL; */
788
789 fputs(df_c, stdout);
790 fflush(stdout);
791
792 if (flags & ROOT_USR) {
793 _err(0, PRINT_PROMPT, _("%s%s: %sRunning as root%s\n"),
794 BOLD, PROGRAM_NAME, _RED, df_c);
795 }
796
797 load_remotes();
798 automount_remotes();
799
800 if (splash_screen) {
801 splash();
802 splash_screen = 0;
803 CLEAR;
804 }
805
806 set_start_path();
807
808 if (ws == (struct ws_t *)NULL || !ws[cur_ws].path || !*ws[cur_ws].path) {
809 _err(0, NOPRINT_PROMPT, _("%s: Fatal error! Failed "
810 "retrieving current working directory\n"), PROGRAM_NAME);
811 exit(EXIT_FAILURE);
812 }
813
814 /* Set terminal window title */
815 if (flags & GUI) {
816 if (xargs.cwd_in_title == 0) {
817 printf("\033]2;%s\007", PROGRAM_NAME);
818 fflush(stdout);
819 } else {
820 set_term_title(ws[cur_ws].path);
821 }
822 }
823
824 exec_profile();
825 load_dirhist();
826 add_to_dirhist(ws[cur_ws].path);
827 get_sel_files();
828
829 /* Start listing as soon as possible to speed up startup time */
830 if (autols && isatty(STDIN_FILENO)) {
831 #ifdef LINUX_INOTIFY
832 /* Initialize inotify */
833 inotify_fd = inotify_init1(IN_NONBLOCK);
834 if (inotify_fd < 0) {
835 _err('w', PRINT_PROMPT, "%s: inotify: %s\n", PROGRAM_NAME,
836 strerror(errno));
837 }
838 #elif defined(BSD_KQUEUE)
839 kq = kqueue();
840 if (kq < 0) {
841 _err('w', PRINT_PROMPT, "%s: kqueue: %s\n", PROGRAM_NAME,
842 strerror(errno));
843 }
844 #endif
845 list_dir();
846 }
847
848 shell = get_sys_shell();
849 create_kbinds_file();
850 load_bookmarks();
851 load_keybinds();
852 load_jumpdb();
853 if (!jump_db || xargs.path == 1)
854 add_to_jumpdb(ws[cur_ws].path);
855
856 initialize_readline();
857
858 /*Trim the directory history file if necessary */
859 check_file_size(dirhist_file, max_dirhist);
860
861 /* Check whether we have a working shell */
862 if (access(user.shell, X_OK) == -1) {
863 _err('w', PRINT_PROMPT, _("%s: %s: System shell not found. "
864 "Please edit the configuration file to specify a working "
865 "shell.\n"), PROGRAM_NAME, user.shell);
866 }
867
868 get_prompt_cmds();
869
870 #ifndef _NO_TRASH
871 if (trash_ok) {
872 trash_n = count_dir(trash_files_dir, NO_CPOP);
873 if (trash_n <= 2)
874 trash_n = 0;
875 }
876 #endif
877
878 if (gethostname(hostname, sizeof(hostname)) == -1) {
879 hostname[0] = '?';
880 hostname[1] = '\0';
881 _err('e', PRINT_PROMPT, _("%s: Error getting hostname\n"),
882 PROGRAM_NAME);
883 }
884
885 init_shell();
886
887 if (config_ok)
888 init_history();
889
890 /* Store history into an array to be able to manipulate it */
891 get_history();
892
893 /* Check if the 'file' command is available: we need it for Lira */
894 /* if (!opener)
895 file_cmd_check(); */
896
897 get_profile_names();
898 load_pinned_dir();
899 set_env();
900
901 /* ###########################
902 * # 2) MAIN PROGRAM LOOP #
903 * ########################### */
904
905 /* This is the main structure of any basic shell
906 1 - Infinite loop
907 2 - Grab user input
908 3 - Parse user input
909 4 - Execute command
910 See https://brennan.io/2015/01/16/write-a-shell-in-c/
911 */
912
913 int i;
914 /* 1) Infinite loop to keep the program running */
915 while (1) {
916 /* 2) Grab input string from the prompt */
917 char *input = prompt();
918 if (!input)
919 continue;
920
921 /* 3) Parse input string */
922 char **cmd = parse_input_str(input);
923 free(input);
924 input = (char *)NULL;
925
926 if (!cmd)
927 continue;
928
929 /* 4) Execute input string */
930 char **alias_cmd = check_for_alias(cmd);
931 if (alias_cmd) {
932 /* If an alias is found, check_for_alias() frees cmd
933 * and returns alias_cmd in its place to be executed by
934 * exec_cmd() */
935 exec_cmd(alias_cmd);
936
937 for (i = 0; alias_cmd[i]; i++)
938 free(alias_cmd[i]);
939 free(alias_cmd);
940 alias_cmd = (char **)NULL;
941 } else {
942 exec_cmd(cmd);
943
944 i = (int)args_n + 1;
945 while (--i >= 0)
946 free(cmd[i]);
947 free(cmd);
948 cmd = (char **)NULL;
949 }
950 }
951
952 return exit_code; /* Never reached */
953 }
954