1 /* bookmarks.c -- bookmarking functions */
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 <errno.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32
33 #include "aux.h"
34 #include "bookmarks.h"
35 #include "checks.h"
36 #include "exec.h"
37 #include "file_operations.h"
38 #include "init.h"
39 #include "mime.h"
40 #include "readline.h"
41 #include "messages.h"
42
43 void
free_bookmarks(void)44 free_bookmarks(void)
45 {
46 if (!bm_n)
47 return;
48
49 size_t i;
50 for (i = 0; i < bm_n; i++) {
51 if (bookmarks[i].shortcut)
52 free(bookmarks[i].shortcut);
53
54 if (bookmarks[i].name)
55 free(bookmarks[i].name);
56
57 if (bookmarks[i].path)
58 free(bookmarks[i].path);
59 }
60
61 free(bookmarks);
62 bookmarks = (struct bookmarks_t *)NULL;
63
64 for (i = 0; bookmark_names[i]; i++)
65 free(bookmark_names[i]);
66 free(bookmark_names);
67 bookmark_names = (char **)NULL;
68 bm_n = 0;
69 return;
70 }
71
72 static char **
bm_prompt(void)73 bm_prompt(void)
74 {
75 char *bm_sel = (char *)NULL;
76 printf(_("%s%s\nEnter '%c' to edit your bookmarks or '%c' to quit.\n"),
77 NC, df_c, 'e', 'q');
78
79 while (!bm_sel)
80 bm_sel = rl_no_hist(_("Choose a bookmark: "));
81
82 char **comm_bm = get_substr(bm_sel, ' ');
83 free(bm_sel);
84 return comm_bm;
85 }
86
87 static void
free_del_elements(char ** elements)88 free_del_elements(char **elements)
89 {
90 size_t i;
91 for (i = 0; elements[i]; i++)
92 free(elements[i]);
93 free(elements);
94 }
95
96 static void
free_bms(char ** _bms,const size_t _bmn)97 free_bms(char **_bms, const size_t _bmn)
98 {
99 size_t i;
100 for (i = 0; i < _bmn; i++)
101 free(_bms[i]);
102 free(_bms);
103 }
104
105 static int
bookmark_del(char * name)106 bookmark_del(char *name)
107 {
108 FILE *bm_fp = NULL;
109 bm_fp = fopen(bm_file, "r");
110 if (!bm_fp)
111 return EXIT_FAILURE;
112
113 size_t i = 0;
114
115 /* Get bookmarks from file */
116 size_t line_size = 0;
117 char *line = (char *)NULL, **bms = (char **)NULL;
118 size_t bmn = 0;
119 ssize_t line_len = 0;
120
121 while ((line_len = getline(&line, &line_size, bm_fp)) > 0) {
122 if (!line || !*line || *line == '#' || *line == '\n')
123 continue;
124
125 int slash = 0;
126 for (i = 0; i < (size_t)line_len; i++) {
127 if (line[i] == '/') {
128 slash = 1;
129 break;
130 }
131 }
132
133 if (!slash)
134 continue;
135
136 if (line[line_len - 1] == '\n')
137 line[line_len - 1] = '\0';
138
139 bms = (char **)xrealloc(bms, (bmn + 1) * sizeof(char *));
140 bms[bmn++] = savestring(line, (size_t)line_len);
141 }
142
143 free(line);
144 line = (char *)NULL;
145
146 if (!bmn) {
147 puts(_("bookmarks: There are no bookmarks"));
148 fclose(bm_fp);
149 return EXIT_SUCCESS;
150 }
151
152 char **del_elements = (char **)NULL;
153 int cmd_line = -1;
154 /* This variable let us know two things: a) bookmark name was
155 * specified in command line; b) the index of this name in the
156 * bookmarks array. It is initialized as -1 since the index name
157 * could be zero */
158
159 if (name) {
160 for (i = 0; i < bmn; i++) {
161 char *bm_name = strbtw(bms[i], ']', ':');
162 if (!bm_name)
163 continue;
164 if (strcmp(name, bm_name) == 0) {
165 free(bm_name);
166 cmd_line = (int)i;
167 break;
168 }
169 free(bm_name);
170 }
171 }
172
173 /* If a valid bookmark name was passed in command line, copy the
174 * corresponding bookmark index (plus 1, as if it were typed in the
175 * bookmarks screen) to the del_elements array */
176 if (cmd_line != -1) {
177 del_elements = (char **)xnmalloc(2, sizeof(char *));
178 del_elements[0] = (char *)xnmalloc((size_t)DIGINUM(cmd_line + 1) + 1, sizeof(char));
179 sprintf(del_elements[0], "%d", cmd_line + 1);
180 del_elements[1] = (char *)NULL;
181 }
182
183 /* If bookmark name was passed but it is not a valid bookmark */
184 else if (name) {
185 fprintf(stderr, _("bookmarks: %s: No such bookmark\n"), name);
186 free_bms(bms, bmn);
187 fclose(bm_fp);
188 return EXIT_FAILURE;
189 }
190
191 /* If not name, list bookmarks and get user input */
192 else {
193 printf(_("%sBookmarks%s\n\n"), BOLD, df_c);
194
195 for (i = 0; i < bmn; i++)
196 printf("%s%zu %s%s%s\n", el_c, i + 1, bm_c, bms[i], df_c);
197
198 /* Get user input */
199 printf(_("\n%sEnter '%c' to quit.\n"), df_c, 'q');
200 char *input = (char *)NULL;
201 while (!input)
202 input = rl_no_hist(_("Bookmark(s) to be deleted "
203 "(ex: 1 2-6, or *): "));
204 del_elements = get_substr(input, ' ');
205 free(input);
206 input = (char *)NULL;
207
208 if (!del_elements) {
209 free_bms(bms, bmn);
210 fclose(bm_fp);
211 fprintf(stderr, _("bookmarks: Error parsing input\n"));
212 return EXIT_FAILURE;
213 }
214 }
215
216 /* We have input */
217 /* If quit */
218 /* I inspect all substrings entered by the user for "q" before any
219 * other value to prevent some accidental deletion, like "1 q", or
220 * worst, "* q" */
221 for (i = 0; del_elements[i]; i++) {
222 int quit = 0;
223
224 if (strcmp(del_elements[i], "q") == 0) {
225 quit = 1;
226 } else if (is_number(del_elements[i]) && (atoi(del_elements[i]) <= 0
227 || atoi(del_elements[i]) > (int)bmn)) {
228 fprintf(stderr, _("bookmarks: %s: No such bookmark\n"),
229 del_elements[i]);
230 quit = 1;
231 }
232
233 if (quit) {
234 free_bms(bms, bmn);
235 free_del_elements(del_elements);
236 fclose(bm_fp);
237 return EXIT_SUCCESS;
238 }
239 }
240
241 /* If "*", simply remove the bookmarks file */
242 /* If there is some "*" in the input line (like "1 5 6-9 *"), it
243 * makes no sense to remove singles bookmarks: Just delete all of
244 * them at once */
245 for (i = 0; del_elements[i]; i++) {
246 if (strcmp(del_elements[i], "*") == 0) {
247 /* Create a backup copy of the bookmarks file, just in case */
248 char *bk_file = (char *)NULL;
249 bk_file = (char *)xcalloc(strlen(config_dir) + 14,
250 sizeof(char));
251 sprintf(bk_file, "%s/bookmarks.bk", config_dir);
252 char *tmp_cmd[] = {"cp", bm_file, bk_file, NULL};
253
254 int ret = launch_execve(tmp_cmd, FOREGROUND, E_NOFLAG);
255 /* Remove the bookmarks file, free stuff, and exit */
256 if (ret == EXIT_SUCCESS) {
257 unlink(bm_file);
258 printf(_("bookmarks: All bookmarks were deleted\n "
259 "However, a backup copy was created (%s)\n"), bk_file);
260 free(bk_file);
261 bk_file = (char *)NULL;
262 } else {
263 printf(_("bookmarks: Error creating backup file. No "
264 "bookmark was deleted\n"));
265 }
266
267 free_bms(bms, bmn);
268 free_del_elements(del_elements);
269 fclose(bm_fp);
270 /* Update bookmark names for TAB completion */
271 /* get_bm_names(); */
272 free_bookmarks();
273 load_bookmarks();
274
275 /* If the argument "*" was specified in command line */
276 if (cmd_line != -1)
277 fputs(_("All bookmarks succesfully removed\n"), stdout);
278
279 return EXIT_SUCCESS;
280 }
281 }
282
283 /* Remove single bookmarks */
284 /* Open a temporary file */
285 char *tmp_file = (char *)NULL;
286 tmp_file = (char *)xnmalloc(strlen(config_dir) + 8, sizeof(char));
287 sprintf(tmp_file, "%s/bm_tmp", config_dir);
288
289 FILE *tmp_fp = fopen(tmp_file, "w+");
290 if (!tmp_fp) {
291 free_bms(bms, bmn);
292 free_del_elements(del_elements);
293 fclose(bm_fp);
294 fprintf(stderr, _("bookmarks: Error creating temporary file\n"));
295
296 return EXIT_FAILURE;
297 }
298
299 /* Go back to the beginning of the bookmarks file */
300 fseek(bm_fp, 0, SEEK_SET);
301
302 /* Dump into the tmp file everything except bookmarks marked for
303 * deletion */
304
305 char *lineb = (char *)NULL;
306 while ((line_len = getline(&lineb, &line_size, bm_fp)) > 0) {
307 if (lineb[line_len - 1] == '\n')
308 lineb[line_len - 1] = '\0';
309
310 int bm_found = 0;
311 size_t j;
312
313 for (j = 0; del_elements[j]; j++) {
314 if (!is_number(del_elements[j]))
315 continue;
316 if (strcmp(bms[atoi(del_elements[j]) - 1], lineb) == 0)
317 bm_found = 1;
318 }
319
320 if (bm_found)
321 continue;
322
323 fprintf(tmp_fp, "%s\n", lineb);
324 }
325
326 free(lineb);
327
328 /* Free stuff */
329 free_del_elements(del_elements);
330 free_bms(bms, bmn);
331
332 fclose(bm_fp);
333 fclose(tmp_fp);
334
335 /* Remove the old bookmarks file and make the tmp file the new
336 * bookmarks file*/
337 unlink(bm_file);
338 rename(tmp_file, bm_file);
339 free(tmp_file);
340
341 /* Update bookmark names for TAB completion */
342 /* get_bm_names(); */
343 free_bookmarks();
344 load_bookmarks();
345
346 /* If the bookmark to be removed was specified in command line */
347 if (cmd_line != -1)
348 printf(_("Successfully removed '%s'\n"), name);
349
350 return EXIT_SUCCESS;
351 }
352
353 static int
bookmark_add(char * file)354 bookmark_add(char *file)
355 {
356 if (!file)
357 return EXIT_FAILURE;
358
359 int mod_file = 0;
360 /* If not absolute path, prepend current path to file */
361 if (*file != '/') {
362 char *tmp_file = (char *)NULL;
363 tmp_file = (char *)xnmalloc((strlen(ws[cur_ws].path) + strlen(file) + 2), sizeof(char));
364 sprintf(tmp_file, "%s/%s", ws[cur_ws].path, file);
365 file = tmp_file;
366 tmp_file = (char *)NULL;
367 mod_file = 1;
368 }
369
370 /* Check if FILE is an available path */
371
372 FILE *bm_fp = fopen(bm_file, "r");
373 if (!bm_fp) {
374 fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n"));
375 if (mod_file)
376 free(file);
377
378 return EXIT_FAILURE;
379 }
380
381 int dup = 0;
382 char **bms = (char **)NULL;
383 size_t line_size = 0, i, bmn = 0;
384 char *line = (char *)NULL;
385
386 while (getline(&line, &line_size, bm_fp) > 0) {
387 if (!line || !*line || *line == '#' || *line == '\n')
388 continue;
389
390 char *tmp_line = (char *)NULL;
391 tmp_line = strchr(line, '/');
392 if (tmp_line) {
393 size_t tmp_line_len = strlen(tmp_line);
394
395 if (tmp_line_len && tmp_line[tmp_line_len - 1] == '\n')
396 tmp_line[tmp_line_len - 1] = '\0';
397
398 if (strcmp(tmp_line, file) == 0) {
399 fprintf(stderr, _("bookmarks: %s: Path already "
400 "bookmarked\n"),
401 file);
402 dup = 1;
403 break;
404 }
405
406 tmp_line = (char *)NULL;
407 }
408
409 /* Store lines: used later to check hotkeys */
410 bms = (char **)xrealloc(bms, (bmn + 1) * sizeof(char *));
411 bms[bmn++] = savestring(line, strlen(line));
412 }
413
414 free(line);
415 line = (char *)NULL;
416 fclose(bm_fp);
417
418 if (dup) {
419 for (i = 0; i < bmn; i++)
420 free(bms[i]);
421 free(bms);
422 if (mod_file)
423 free(file);
424 return EXIT_FAILURE;
425 }
426
427 /* If path is available */
428
429 char *name = (char *)NULL, *hk = (char *)NULL, *tmp = (char *)NULL;
430
431 /* Ask for data to construct the bookmark line. Both values could be
432 * NULL */
433 puts(_("Bookmark line example: [sc]name:path"));
434 hk = rl_no_hist("Shortcut: ");
435
436 /* Check if hotkey is available */
437 if (hk) {
438 char *tmp_line = (char *)NULL;
439
440 for (i = 0; i < bmn; i++) {
441 tmp_line = strbtw(bms[i], '[', ']');
442 if (tmp_line) {
443 if (strcmp(hk, tmp_line) == 0) {
444 fprintf(stderr, _("bookmarks: %s: This shortcut is "
445 "already in use\n"), hk);
446
447 dup = 1;
448 free(tmp_line);
449 break;
450 }
451
452 free(tmp_line);
453 }
454 }
455 }
456
457 if (dup) {
458 if (hk)
459 free(hk);
460 for (i = 0; i < bmn; i++)
461 free(bms[i]);
462 free(bms);
463 if (mod_file)
464 free(file);
465 return EXIT_FAILURE;
466 }
467
468 name = rl_no_hist("Name: ");
469
470 if (name) {
471 /* Check name is not duplicated */
472 char *tmp_line = (char *)NULL;
473 for (i = 0; i < bmn; i++) {
474 tmp_line = strbtw(bms[i], ']', ':');
475 if (tmp_line) {
476 if (strcmp(name, tmp_line) == 0) {
477 fprintf(stderr, _("bookmarks: %s: This name is "
478 "already in use\n"), name);
479 dup = 1;
480 free(tmp_line);
481 break;
482 }
483 free(tmp_line);
484 }
485 }
486
487 if (dup) {
488 free(name);
489 if (hk)
490 free(hk);
491 for (i = 0; i < bmn; i++)
492 free(bms[i]);
493 free(bms);
494 if (mod_file)
495 free(file);
496 return EXIT_FAILURE;
497 }
498
499 /* Generate the bookmark line */
500 if (hk) { /* name AND hk */
501 tmp = (char *)xcalloc(strlen(hk) + strlen(name) + strlen(file) + 5, sizeof(char));
502 sprintf(tmp, "[%s]%s:%s\n", hk, name, file);
503 free(hk);
504 } else { /* Only name */
505 tmp = (char *)xnmalloc(strlen(name) + strlen(file) + 3,
506 sizeof(char));
507 sprintf(tmp, "%s:%s\n", name, file);
508 }
509
510 free(name);
511 name = (char *)NULL;
512 }
513
514 else if (hk) { /* Only hk */
515 tmp = (char *)xnmalloc(strlen(hk) + strlen(file) + 4,
516 sizeof(char));
517 sprintf(tmp, "[%s]%s\n", hk, file);
518 free(hk);
519 hk = (char *)NULL;
520 } else { /* Neither shortcut nor name: only path */
521 tmp = (char *)xnmalloc(strlen(file) + 2, sizeof(char));
522 sprintf(tmp, "%s\n", file);
523 }
524
525 for (i = 0; i < bmn; i++)
526 free(bms[i]);
527 free(bms);
528 bms = (char **)NULL;
529
530 if (!tmp) {
531 fprintf(stderr, _("bookmarks: Error generating the bookmark line\n"));
532 return EXIT_FAILURE;
533 }
534
535 /* Once we have the bookmark line, write it to the bookmarks file */
536
537 bm_fp = fopen(bm_file, "a+");
538 if (!bm_fp) {
539 fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n"));
540 free(tmp);
541 return EXIT_FAILURE;
542 }
543
544 if (mod_file)
545 free(file);
546
547 if (fseek(bm_fp, 0L, SEEK_END) == -1) {
548 fprintf(stderr, _("bookmarks: Error opening the bookmarks file\n"));
549 free(tmp);
550 fclose(bm_fp);
551 return EXIT_FAILURE;
552 }
553
554 /* Everything is fine: add the new bookmark to the bookmarks file */
555 fprintf(bm_fp, "%s", tmp);
556 fclose(bm_fp);
557 printf(_("File succesfully bookmarked\n"));
558 free(tmp);
559 /* Update bookmark names for TAB completion */
560 /* get_bm_names(); */
561 free_bookmarks();
562 load_bookmarks();
563 return EXIT_SUCCESS;
564 }
565
566 int
edit_bookmarks(char * cmd)567 edit_bookmarks(char *cmd)
568 {
569 int exit_status = EXIT_SUCCESS;
570
571 if (!cmd) {
572 open_in_foreground = 1;
573 exit_status = open_file(bm_file);
574 open_in_foreground = 0;
575 } else {
576 char *tmp_cmd[] = {cmd, bm_file, NULL};
577 if (launch_execve(tmp_cmd, FOREGROUND, E_NOSTDERR) != EXIT_SUCCESS)
578 exit_status = EXIT_FAILURE;
579 }
580
581 if (exit_status == EXIT_FAILURE)
582 fprintf(stderr, _("%s: Cannot open the bookmarks file"), PROGRAM_NAME);
583
584 return exit_status;
585 }
586
587 int
open_bookmark(void)588 open_bookmark(void)
589 {
590 /* If no bookmarks */
591 if (bm_n == 0) {
592 printf(_("Bookmarks: There are no bookmarks\nEnter 'bm edit' "
593 "or press F11 to edit the bookmarks file. You can "
594 "also enter 'bm add PATH' to add a new bookmark\n"));
595 return EXIT_SUCCESS;
596 }
597
598 /* We have bookmarks... */
599 struct stat file_attrib;
600
601 if (clear_screen)
602 CLEAR;
603
604 printf(_("%sBookmarks Manager%s\n\n"), BOLD, df_c);
605
606 /* Print bookmarks taking into account the existence of shortcut,
607 * name, and path for each bookmark */
608 size_t i, eln = 0;
609
610 for (i = 0; i < bm_n; i++) {
611 if (!bookmarks[i].path || !*bookmarks[i].path)
612 continue;
613 eln++;
614 int is_dir = 0, sc_ok = 0, name_ok = 0, non_existent = 0;
615 int path_ok = stat(bookmarks[i].path, &file_attrib);
616
617 if (bookmarks[i].shortcut)
618 sc_ok = 1;
619
620 if (bookmarks[i].name)
621 name_ok = 1;
622
623 if (path_ok == -1) {
624 non_existent = 1;
625 } else {
626 switch ((file_attrib.st_mode & S_IFMT)) {
627 case S_IFDIR: is_dir = 1; break;
628 case S_IFREG: break;
629 default: non_existent = 1; break;
630 }
631 }
632
633 printf("%s%zu%s %s%c%s%c%s %s%s%s\n", el_c, eln, df_c,
634 BOLD, sc_ok ? '[' : 0, sc_ok ? bookmarks[i].shortcut : "",
635 sc_ok ? ']' : 0, df_c, non_existent ? GRAY : (is_dir ? bm_c : fi_c),
636 name_ok ? bookmarks[i].name : bookmarks[i].path, df_c);
637 }
638
639 /* User selection. Display the prompt */
640 char **arg = bm_prompt();
641 if (!arg || !*arg)
642 return EXIT_FAILURE;
643
644 int exit_status = EXIT_SUCCESS;
645
646 /* Case "edit" */
647 if (*arg[0] == 'e' && (!arg[0][1] || strcmp(arg[0], "edit") == 0)) {
648 stat(bm_file, &file_attrib);
649 time_t mtime_bfr = (time_t)file_attrib.st_mtime;
650
651 edit_bookmarks(arg[1] ? arg[1] : NULL);
652
653 stat(bm_file, &file_attrib);
654 if (mtime_bfr != (time_t)file_attrib.st_mtime) {
655 free_bookmarks();
656 load_bookmarks();
657 }
658
659 for (i = 0; arg[i]; i++)
660 free(arg[i]);
661 free(arg);
662
663 arg = (char **)NULL;
664
665 char *tmp_cmd[] = {"bm", NULL};
666 bookmarks_function(tmp_cmd);
667 return EXIT_SUCCESS;
668 }
669
670 /* Case "quit" */
671 if (*arg[0] == 'q' && (!arg[0][1] || strcmp(arg[0], "quit") == 0))
672 goto FREE_AND_EXIT;
673
674 char *tmp_path = (char *)NULL;
675
676 /* Get the corresponding bookmark path */
677 /* If an ELN */
678 if (is_number(arg[0])) {
679 int num = atoi(arg[0]);
680 if (num <= 0 || (size_t)num > bm_n) {
681 fprintf(stderr, _("Bookmarks: %d: No such ELN\n"), num);
682 exit_status = EXIT_FAILURE;
683 goto FREE_AND_EXIT;
684 } else {
685 tmp_path = bookmarks[num - 1].path;
686 }
687 } else {
688 /* If string, check shortcuts and names */
689 for (i = 0; i < bm_n; i++) {
690 if ((bookmarks[i].shortcut && *arg[0] == *bookmarks[i].shortcut
691 && strcmp(arg[0], bookmarks[i].shortcut) == 0)
692 || (bookmarks[i].name && *arg[0] == *bookmarks[i].name
693 && strcmp(arg[0], bookmarks[i].name) == 0)) {
694
695 if (bookmarks[i].path) {
696 char *tmp_cmd[] = {"o", bookmarks[i].path,
697 arg[1] ? arg[1] : NULL,
698 NULL};
699
700 exit_status = open_function(tmp_cmd);
701 goto FREE_AND_EXIT;
702 }
703
704 fprintf(stderr, _("%s: %s: Invalid bookmark\n"),
705 PROGRAM_NAME, arg[0]);
706 exit_status = EXIT_FAILURE;
707 goto FREE_AND_EXIT;
708 }
709 }
710 }
711
712 if (!tmp_path) {
713 fprintf(stderr, _("Bookmarks: %s: No such bookmark\n"),
714 arg[0]);
715 exit_status = EXIT_FAILURE;
716 goto FREE_AND_EXIT;
717 }
718
719 char *tmp_cmd[] = {"o", tmp_path, arg[1] ? arg[1] : NULL, NULL};
720 exit_status = open_function(tmp_cmd);
721 goto FREE_AND_EXIT;
722
723 FREE_AND_EXIT : {
724 for (i = 0; arg[i]; i++)
725 free(arg[i]);
726 free(arg);
727 arg = (char **)NULL;
728 return exit_status;
729 }
730 }
731
732 int
bookmarks_function(char ** cmd)733 bookmarks_function(char **cmd)
734 {
735 if (xargs.stealth_mode == 1) {
736 printf(_("%s: Access to configuration files is not allowed in "
737 "stealth mode\n"), PROGRAM_NAME);
738 return EXIT_SUCCESS;
739 }
740
741 if (!config_ok) {
742 fprintf(stderr, _("Bookmarks function disabled\n"));
743 return EXIT_FAILURE;
744 }
745
746 /* If the bookmarks file doesn't exist, create it. NOTE: This file
747 * should be created at startup (by get_bm_names()), but we check
748 * it again here just in case it was meanwhile deleted for some
749 * reason */
750
751 /* If no arguments */
752 if (!cmd[1])
753 return open_bookmark();
754
755 /* Check arguments */
756
757 /* Add a bookmark */
758 if (*cmd[1] == 'a' && (!cmd[1][1] || strcmp(cmd[1], "add") == 0)) {
759 if (!cmd[2]) {
760 puts(_(BOOKMARKS_USAGE));
761 return EXIT_SUCCESS;
762 }
763
764 if (access(cmd[2], F_OK) != 0) {
765 fprintf(stderr, _("Bookmarks: %s: %s\n"), cmd[2],
766 strerror(errno));
767 return EXIT_FAILURE;
768 }
769
770 return bookmark_add(cmd[2]);
771 }
772
773 /* Delete bookmarks */
774 if (*cmd[1] == 'd' && (!cmd[1][1] || strcmp(cmd[1], "del") == 0))
775 return bookmark_del(cmd[2] ? cmd[2] : NULL);
776
777 /* Edit */
778 if (*cmd[1] == 'e' && (!cmd[1][1] || strcmp(cmd[1], "edit") == 0))
779 return edit_bookmarks(cmd[2] ? cmd[2] : NULL);
780
781 /* Shortcut, bm name, or (if expand_bookmarks) bm path */
782 size_t i;
783 for (i = 0; i < bm_n; i++) {
784 if ((bookmarks[i].shortcut && *cmd[1] == *bookmarks[i].shortcut
785 && strcmp(cmd[1], bookmarks[i].shortcut) == 0)
786
787 || (bookmarks[i].name && *cmd[1] == *bookmarks[i].name
788 && strcmp(cmd[1], bookmarks[i].name) == 0)
789
790 || (expand_bookmarks && bookmarks[i].path
791 && *cmd[1] == *bookmarks[i].path
792 && strcmp(cmd[1], bookmarks[i].path) == 0)) {
793
794 if (bookmarks[i].path) {
795 char *tmp_cmd[] = {"o", bookmarks[i].path,
796 cmd[2] ? cmd[2] : NULL, NULL};
797 return open_function(tmp_cmd);
798 }
799
800 fprintf(stderr, _("Bookmarks: %s: Invalid bookmark\n"),
801 cmd[1]);
802 return EXIT_FAILURE;
803 }
804 }
805
806 fprintf(stderr, _("Bookmarks: %s: No such bookmark\n"), cmd[1]);
807 return EXIT_FAILURE;
808 }
809