This source file includes following definitions.
- strip_ext
- check_patterns
- extract_arg
- test_type
- test_condition
- debug_out
- test_line
- execute_menu_command
- menu_file_own
- check_format_view
- check_format_cd
- check_format_var
- expand_format
- user_menu_cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <config.h>
32
33 #include <ctype.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "lib/global.h"
40 #include "lib/fileloc.h"
41 #include "lib/tty/tty.h"
42 #include "lib/skin.h"
43 #include "lib/search.h"
44 #include "lib/vfs/vfs.h"
45 #include "lib/strutil.h"
46 #include "lib/util.h"
47
48 #ifdef USE_INTERNAL_EDIT
49 #include "src/editor/edit.h"
50 #endif
51 #include "src/viewer/mcviewer.h"
52
53 #include "src/args.h"
54 #include "src/execute.h"
55 #include "src/setup.h"
56 #include "src/history.h"
57
58 #include "src/filemanager/dir.h"
59 #include "src/filemanager/filemanager.h"
60 #include "src/filemanager/layout.h"
61
62 #include "usermenu.h"
63
64
65
66
67
68 #define MAX_ENTRIES 16
69 #define MAX_ENTRY_LEN 60
70
71
72
73
74
75
76
77 static gboolean debug_flag = FALSE;
78 static gboolean debug_error = FALSE;
79 static char *menu = NULL;
80
81
82
83
84
85
86 static char *
87 strip_ext (char *ss)
88 {
89 char *s;
90 char *e = NULL;
91
92 if (ss == NULL)
93 return NULL;
94
95 for (s = ss; *s != '\0'; s++)
96 {
97 if (*s == '.')
98 e = s;
99 if (IS_PATH_SEP (*s) && e != NULL)
100 e = NULL;
101 }
102
103 if (e != NULL)
104 *e = '\0';
105
106 return (*ss == '\0' ? NULL : ss);
107 }
108
109
110
111
112
113
114
115
116 static char *
117 check_patterns (char *p)
118 {
119 static const char def_name[] = "shell_patterns=";
120 char *p0 = p;
121
122 if (strncmp (p, def_name, sizeof (def_name) - 1) != 0)
123 return p0;
124
125 p += sizeof (def_name) - 1;
126 if (*p == '1')
127 easy_patterns = TRUE;
128 else if (*p == '0')
129 easy_patterns = FALSE;
130 else
131 return p0;
132
133
134 p++;
135 while (whiteness (*p))
136 p++;
137 return p;
138 }
139
140
141
142
143
144 static char *
145 extract_arg (char *p, char *arg, int size)
146 {
147 while (*p != '\0' && whiteness (*p))
148 p++;
149
150
151 while (*p != '\0' && (*p != ' ' || *(p - 1) == '\\') && *p != '\t' && *p != '\n')
152 {
153 char *np;
154
155 np = str_get_next_char (p);
156 if (np - p >= size)
157 break;
158 memcpy (arg, p, np - p);
159 arg += np - p;
160 size -= np - p;
161 p = np;
162 }
163 *arg = '\0';
164 if (*p == '\0' || *p == '\n')
165 str_prev_char (&p);
166 return p;
167 }
168
169
170
171
172
173 static gboolean
174 test_type (WPanel *panel, char *arg)
175 {
176 const file_entry_t *fe;
177 int result = 0;
178 mode_t st_mode;
179
180 fe = panel_current_entry (panel);
181 if (fe == NULL)
182 return FALSE;
183
184 st_mode = fe->st.st_mode;
185
186 for (; *arg != '\0'; arg++)
187 {
188 switch (*arg)
189 {
190 case 'n':
191 result |= !S_ISDIR (st_mode);
192 break;
193 case 'r':
194 result |= S_ISREG (st_mode);
195 break;
196 case 'd':
197 result |= S_ISDIR (st_mode);
198 break;
199 case 'l':
200 result |= S_ISLNK (st_mode);
201 break;
202 case 'c':
203 result |= S_ISCHR (st_mode);
204 break;
205 case 'b':
206 result |= S_ISBLK (st_mode);
207 break;
208 case 'f':
209 result |= S_ISFIFO (st_mode);
210 break;
211 case 's':
212 result |= S_ISSOCK (st_mode);
213 break;
214 case 'x':
215 result |= (st_mode & 0111) != 0 ? 1 : 0;
216 break;
217 case 't':
218 result |= panel->marked != 0 ? 1 : 0;
219 break;
220 default:
221 debug_error = TRUE;
222 break;
223 }
224 }
225
226 return (result != 0);
227 }
228
229
230
231
232
233 static char *
234 test_condition (const Widget *edit_widget, char *p, gboolean *condition)
235 {
236 char arg[256];
237 const mc_search_type_t search_type = easy_patterns ? MC_SEARCH_T_GLOB : MC_SEARCH_T_REGEX;
238 #ifdef USE_INTERNAL_EDIT
239 const WEdit *e = CONST_EDIT (edit_widget);
240 #endif
241
242
243 for (; *p != '\n' && *p != '&' && *p != '|'; p++)
244 {
245 WPanel *panel = NULL;
246
247
248 if ((*p == ' ' && *(p - 1) != '\\') || *p == '\t')
249 continue;
250 if (*p >= 'a')
251 panel = current_panel;
252 else if (get_other_type () == view_listing)
253 panel = other_panel;
254
255 *p |= 0x20;
256
257 switch (*p++)
258 {
259 case '!':
260 p = test_condition (edit_widget, p, condition);
261 *condition = !*condition;
262 str_prev_char (&p);
263 break;
264 case 'f':
265 p = extract_arg (p, arg, sizeof (arg));
266 #ifdef USE_INTERNAL_EDIT
267 if (e != NULL)
268 {
269 const char *edit_filename;
270
271 edit_filename = edit_get_file_name (e);
272 *condition = mc_search (arg, DEFAULT_CHARSET, edit_filename, search_type);
273 }
274 else
275 #endif
276 {
277 if (panel == NULL)
278 *condition = FALSE;
279 else
280 {
281 const file_entry_t *fe;
282
283 fe = panel_current_entry (panel);
284 *condition = fe != NULL
285 && mc_search (arg, DEFAULT_CHARSET, fe->fname->str, search_type);
286 }
287 }
288 break;
289 case 'y':
290 #ifdef USE_INTERNAL_EDIT
291 if (e != NULL)
292 {
293 const char *syntax_type;
294
295 syntax_type = edit_get_syntax_type (e);
296 if (syntax_type != NULL)
297 {
298 p = extract_arg (p, arg, sizeof (arg));
299 *condition = mc_search (arg, DEFAULT_CHARSET, syntax_type, MC_SEARCH_T_NORMAL);
300 }
301 }
302 #endif
303 break;
304 case 'd':
305 p = extract_arg (p, arg, sizeof (arg));
306 *condition = panel != NULL
307 && mc_search (arg, DEFAULT_CHARSET, vfs_path_as_str (panel->cwd_vpath),
308 search_type);
309 break;
310 case 't':
311 p = extract_arg (p, arg, sizeof (arg));
312 *condition = panel != NULL && test_type (panel, arg);
313 break;
314 case 'x':
315 {
316 struct stat status;
317
318 p = extract_arg (p, arg, sizeof (arg));
319 *condition = stat (arg, &status) == 0 && is_exe (status.st_mode);
320 break;
321 }
322 default:
323 debug_error = TRUE;
324 break;
325 }
326 }
327 return p;
328 }
329
330
331
332
333 static void
334 debug_out (char *start, char *end, gboolean condition)
335 {
336 static char *msg = NULL;
337
338 if (start == NULL && end == NULL)
339 {
340
341 if (debug_flag && msg != NULL)
342 {
343 size_t len;
344
345 len = strlen (msg);
346 if (len != 0)
347 msg[len - 1] = '\0';
348 message (D_NORMAL, _("Debug"), "%s", msg);
349
350 }
351 debug_flag = FALSE;
352 MC_PTR_FREE (msg);
353 }
354 else
355 {
356 const char *type;
357 char *p;
358
359
360 if (!debug_flag)
361 return;
362
363 if (debug_error)
364 {
365 type = _("ERROR:");
366 debug_error = FALSE;
367 }
368 else if (condition)
369 type = _("True:");
370 else
371 type = _("False:");
372
373 if (end == NULL)
374 p = g_strdup_printf ("%s %s %c \n", msg ? msg : "", type, *start);
375 else
376 p = g_strdup_printf ("%s %s %.*s \n", msg ? msg : "", type, (int) (end - start), start);
377 g_free (msg);
378 msg = p;
379 }
380 }
381
382
383
384
385
386 static char *
387 test_line (const Widget *edit_widget, char *p, gboolean *result)
388 {
389 char operator;
390
391
392 while (*p != '\0' && *p != '\n')
393 {
394 char *debug_start, *debug_end;
395 gboolean condition = TRUE;
396
397
398 while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t')
399 p++;
400 if (*p == '\0' || *p == '\n')
401 break;
402 operator = *p++;
403 if (*p == '?')
404 {
405 debug_flag = TRUE;
406 p++;
407 }
408
409 while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t')
410 p++;
411 if (*p == '\0' || *p == '\n')
412 break;
413
414 debug_start = p;
415 p = test_condition (edit_widget, p, &condition);
416 debug_end = p;
417
418 debug_out (debug_start, debug_end, condition);
419
420 switch (operator)
421 {
422 case '+':
423 case '=':
424
425 *result = condition;
426 break;
427 case '&':
428 *result = *result && condition;
429 break;
430 case '|':
431 *result = *result || condition;
432 break;
433 default:
434 debug_error = TRUE;
435 break;
436 }
437
438 debug_out (&operator, NULL, *result);
439
440 }
441
442 debug_out (NULL, NULL, TRUE);
443
444 if (*p == '\0' || *p == '\n')
445 str_prev_char (&p);
446 return p;
447 }
448
449
450
451
452 static void
453 execute_menu_command (const Widget *edit_widget, const char *commands, gboolean show_prompt)
454 {
455 FILE *cmd_file;
456 int cmd_file_fd;
457 gboolean expand_prefix_found = FALSE;
458 char *parameter = NULL;
459 gboolean do_quote = FALSE;
460 char lc_prompt[80];
461 int col;
462 vfs_path_t *file_name_vpath;
463 gboolean run_view = FALSE;
464 char *cmd;
465
466
467 commands = strchr (commands, '\n');
468 if (commands == NULL)
469 return;
470
471 cmd_file_fd = mc_mkstemps (&file_name_vpath, "mcusr", SCRIPT_SUFFIX);
472
473 if (cmd_file_fd == -1)
474 {
475 message (D_ERROR, MSG_ERROR, _("Cannot create temporary command file\n%s"),
476 unix_error_string (errno));
477 return;
478 }
479
480 cmd_file = fdopen (cmd_file_fd, "w");
481 fputs ("#! /bin/sh\n", cmd_file);
482 commands++;
483
484 for (col = 0; *commands != '\0'; commands++)
485 {
486 if (col == 0)
487 {
488 if (!whitespace (*commands))
489 break;
490 while (whitespace (*commands))
491 commands++;
492 if (*commands == '\0')
493 break;
494 }
495 col++;
496 if (*commands == '\n')
497 col = 0;
498 if (parameter != NULL)
499 {
500 if (*commands == '}')
501 {
502 *parameter = '\0';
503 parameter =
504 input_dialog (_("Parameter"), lc_prompt, MC_HISTORY_FM_MENU_EXEC_PARAM, "",
505 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD |
506 INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_VARIABLES |
507 INPUT_COMPLETE_USERNAMES);
508 if (parameter == NULL || *parameter == '\0')
509 {
510
511 g_free (parameter);
512 fclose (cmd_file);
513 mc_unlink (file_name_vpath);
514 vfs_path_free (file_name_vpath, TRUE);
515 return;
516 }
517 if (do_quote)
518 {
519 char *tmp;
520
521 tmp = name_quote (parameter, FALSE);
522 if (tmp != NULL)
523 {
524 fputs (tmp, cmd_file);
525 g_free (tmp);
526 }
527 }
528 else
529 fputs (parameter, cmd_file);
530
531 MC_PTR_FREE (parameter);
532 }
533 else if (parameter < lc_prompt + sizeof (lc_prompt) - 1)
534 *parameter++ = *commands;
535 }
536 else if (expand_prefix_found)
537 {
538 expand_prefix_found = FALSE;
539 if (g_ascii_isdigit ((gchar) * commands))
540 {
541 do_quote = (atoi (commands) != 0);
542 while (g_ascii_isdigit ((gchar) * commands))
543 commands++;
544 }
545 if (*commands == '{')
546 parameter = lc_prompt;
547 else
548 {
549 char *text;
550
551 text = expand_format (edit_widget, *commands, do_quote);
552 if (text != NULL)
553 {
554 fputs (text, cmd_file);
555 g_free (text);
556 }
557 }
558 }
559 else if (*commands == '%')
560 {
561 int i;
562
563 i = check_format_view (commands + 1);
564 if (i != 0)
565 {
566 commands += i;
567 run_view = TRUE;
568 }
569 else
570 {
571 do_quote = TRUE;
572 expand_prefix_found = TRUE;
573 }
574 }
575 else
576 fputc (*commands, cmd_file);
577 }
578
579 fclose (cmd_file);
580 mc_chmod (file_name_vpath, S_IRWXU);
581
582
583 cmd = g_strconcat ("/bin/sh ", vfs_path_as_str (file_name_vpath), (char *) NULL);
584
585 if (run_view)
586 {
587 mcview_viewer (cmd, NULL, 0, 0, 0);
588 dialog_switch_process_pending ();
589 }
590 else if (show_prompt)
591 shell_execute (cmd, EXECUTE_HIDE);
592 else
593 {
594 gboolean ok;
595
596
597
598 tty_reset_shell_mode ();
599
600 ok = (system (cmd) != -1);
601
602
603 tty_raw_mode ();
604
605
606 tty_clear_screen ();
607 repaint_screen ();
608
609 if (!ok)
610 message (D_ERROR, MSG_ERROR, "%s", _("Error calling program"));
611 }
612
613 g_free (cmd);
614
615 mc_unlink (file_name_vpath);
616 vfs_path_free (file_name_vpath, TRUE);
617 }
618
619
620
621
622
623
624
625
626
627
628 static gboolean
629 menu_file_own (char *path)
630 {
631 struct stat st;
632
633 if (stat (path, &st) == 0 && (st.st_uid == 0 || (st.st_uid == geteuid ()) != 0)
634 && ((st.st_mode & (S_IWGRP | S_IWOTH)) == 0))
635 return TRUE;
636
637 if (verbose)
638 message (D_NORMAL, _("Warning -- ignoring file"),
639 _("File %s is not owned by root or you or is world writable.\n"
640 "Using it may compromise your security"), path);
641
642 return FALSE;
643 }
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674 int
675 check_format_view (const char *p)
676 {
677 const char *q = p;
678
679 if (strncmp (p, "view", 4) == 0)
680 {
681 q += 4;
682 if (*q == '{')
683 {
684 for (q++; *q != '\0' && *q != '}'; q++)
685 {
686 if (strncmp (q, DEFAULT_CHARSET, 5) == 0)
687 {
688 mcview_global_flags.hex = FALSE;
689 q += 4;
690 }
691 else if (strncmp (q, "hex", 3) == 0)
692 {
693 mcview_global_flags.hex = TRUE;
694 q += 2;
695 }
696 else if (strncmp (q, "nroff", 5) == 0)
697 {
698 mcview_global_flags.nroff = TRUE;
699 q += 4;
700 }
701 else if (strncmp (q, "unform", 6) == 0)
702 {
703 mcview_global_flags.nroff = FALSE;
704 q += 5;
705 }
706 }
707 if (*q == '}')
708 q++;
709 }
710 return q - p;
711 }
712 return 0;
713 }
714
715
716
717 int
718 check_format_cd (const char *p)
719 {
720 return (strncmp (p, "cd", 2)) != 0 ? 0 : 3;
721 }
722
723
724
725
726
727
728 int
729 check_format_var (const char *p, char **v)
730 {
731 *v = NULL;
732
733 if (strncmp (p, "var{", 4) == 0)
734 {
735 const char *q = p;
736 const char *dots = NULL;
737 const char *value;
738 char *var_name;
739
740 for (q += 4; *q != '\0' && *q != '}'; q++)
741 {
742 if (*q == ':')
743 dots = q + 1;
744 }
745 if (*q == '\0')
746 return 0;
747
748 if (dots == NULL || dots == q + 5)
749 {
750 message (D_ERROR,
751 _("Format error on file Extensions File"),
752 dots == NULL ? _("The %%var macro has no default")
753 : _("The %%var macro has no variable"));
754 return 0;
755 }
756
757
758 var_name = g_strndup (p + 4, dots - 2 - (p + 3));
759 value = getenv (var_name);
760 g_free (var_name);
761
762 if (value != NULL)
763 *v = g_strdup (value);
764 else
765 *v = g_strndup (dots, q - dots);
766
767 return q - p;
768 }
769 return 0;
770 }
771
772
773
774 char *
775 expand_format (const Widget *edit_widget, char c, gboolean do_quote)
776 {
777 WPanel *panel = NULL;
778 char *(*quote_func) (const char *, gboolean);
779 const char *fname = NULL;
780 char *result;
781 char c_lc;
782
783 #ifdef USE_INTERNAL_EDIT
784 const WEdit *e = CONST_EDIT (edit_widget);
785 #else
786 (void) edit_widget;
787 #endif
788
789 if (c == '%')
790 return g_strdup ("%");
791
792 switch (mc_global.mc_run_mode)
793 {
794 case MC_RUN_FULL:
795 #ifdef USE_INTERNAL_EDIT
796 if (e != NULL)
797 fname = edit_get_file_name (e);
798 else
799 #endif
800 {
801 const file_entry_t *fe;
802
803 if (g_ascii_islower ((gchar) c))
804 panel = current_panel;
805 else
806 {
807 if (get_other_type () != view_listing)
808 return NULL;
809 panel = other_panel;
810 }
811
812 fe = panel_current_entry (panel);
813 fname = fe == NULL ? NULL : fe->fname->str;
814 }
815 break;
816
817 #ifdef USE_INTERNAL_EDIT
818 case MC_RUN_EDITOR:
819 fname = edit_get_file_name (e);
820 break;
821 #endif
822
823 case MC_RUN_VIEWER:
824
825 fname = (const char *) mc_run_param0;
826 break;
827
828 default:
829
830 return NULL;
831 }
832
833 if (do_quote)
834 quote_func = name_quote;
835 else
836 quote_func = fake_name_quote;
837
838 c_lc = g_ascii_tolower ((gchar) c);
839
840 switch (c_lc)
841 {
842 case 'f':
843 case 'p':
844 result = quote_func (fname, FALSE);
845 goto ret;
846 case 'x':
847 result = quote_func (extension (fname), FALSE);
848 goto ret;
849 case 'd':
850 {
851 const char *cwd;
852
853 if (panel != NULL)
854 cwd = vfs_path_as_str (panel->cwd_vpath);
855 else
856 cwd = vfs_get_current_dir ();
857
858 result = quote_func (cwd, FALSE);
859 goto ret;
860 }
861 case 'c':
862 #ifdef USE_INTERNAL_EDIT
863 if (e != NULL)
864 {
865 result = g_strdup_printf ("%u", (unsigned int) edit_get_cursor_offset (e));
866 goto ret;
867 }
868 #endif
869 break;
870 case 'i':
871 #ifdef USE_INTERNAL_EDIT
872 if (e != NULL)
873 {
874 result = g_strnfill (edit_get_curs_col (e), ' ');
875 goto ret;
876 }
877 #endif
878 break;
879 case 'y':
880 #ifdef USE_INTERNAL_EDIT
881 if (e != NULL)
882 {
883 const char *syntax_type;
884
885 syntax_type = edit_get_syntax_type (e);
886 if (syntax_type != NULL)
887 {
888 result = g_strdup (syntax_type);
889 goto ret;
890 }
891 }
892 #endif
893 break;
894 case 'k':
895 case 'b':
896 #ifdef USE_INTERNAL_EDIT
897 if (e != NULL)
898 {
899 char *file;
900
901 file = mc_config_get_full_path (EDIT_HOME_BLOCK_FILE);
902 result = quote_func (file, FALSE);
903 g_free (file);
904 goto ret;
905 }
906 #endif
907 if (c_lc == 'b')
908 {
909 result = strip_ext (quote_func (fname, FALSE));
910 goto ret;
911 }
912 break;
913 case 'n':
914 #ifdef USE_INTERNAL_EDIT
915 if (e != NULL)
916 {
917 result = strip_ext (quote_func (fname, FALSE));
918 goto ret;
919 }
920 #endif
921 break;
922 case 'm':
923 if (menu != NULL)
924 {
925 result = quote_func (menu, FALSE);
926 goto ret;
927 }
928 break;
929 case 's':
930 if (panel == NULL || panel->marked == 0)
931 {
932 result = quote_func (fname, FALSE);
933 goto ret;
934 }
935
936 MC_FALLTHROUGH;
937
938 case 't':
939 case 'u':
940 {
941 GString *block = NULL;
942 int i;
943
944 if (panel == NULL)
945 {
946 result = NULL;
947 goto ret;
948 }
949
950 for (i = 0; i < panel->dir.len; i++)
951 if (panel->dir.list[i].f.marked != 0)
952 {
953 char *tmp;
954
955 tmp = quote_func (panel->dir.list[i].fname->str, FALSE);
956 if (tmp != NULL)
957 {
958 if (block == NULL)
959 block = g_string_new_take (tmp);
960 else
961 {
962 g_string_append (block, tmp);
963 g_free (tmp);
964 }
965 g_string_append_c (block, ' ');
966 }
967
968 if (c_lc == 'u')
969 do_file_mark (panel, i, 0);
970 }
971 result = block == NULL ? NULL : g_string_free (block, block->len == 0);
972 goto ret;
973 }
974 default:
975 break;
976 }
977
978 result = g_strdup ("% ");
979 result[1] = c;
980 ret:
981 return result;
982 }
983
984
985
986
987
988
989
990 gboolean
991 user_menu_cmd (const Widget *edit_widget, const char *menu_file, int selected_entry)
992 {
993 char *data, *p;
994 GPtrArray *entries = NULL;
995 int max_cols = 0;
996 int col = 0;
997 gboolean accept_entry = TRUE;
998 int selected = 0;
999 gboolean old_patterns;
1000 gboolean res = FALSE;
1001 gboolean interactive = TRUE;
1002
1003 if (!vfs_current_is_local ())
1004 {
1005 message (D_ERROR, MSG_ERROR, "%s", _("Cannot execute commands on non-local filesystems"));
1006 return FALSE;
1007 }
1008
1009 menu = g_strdup (menu_file != NULL ? menu_file : edit_widget != NULL ?
1010 EDIT_LOCAL_MENU : MC_LOCAL_MENU);
1011
1012 if (!exist_file (menu) || !menu_file_own (menu))
1013 {
1014 if (menu_file != NULL)
1015 {
1016 message (D_ERROR, MSG_ERROR, _("Cannot open file %s\n%s"), menu,
1017 unix_error_string (errno));
1018 MC_PTR_FREE (menu);
1019 return FALSE;
1020 }
1021
1022 g_free (menu);
1023 menu = mc_config_get_full_path (edit_widget != NULL ? EDIT_HOME_MENU : MC_USERMENU_FILE);
1024 if (!exist_file (menu))
1025 {
1026 const char *global_menu;
1027
1028 global_menu = edit_widget != NULL ? EDIT_GLOBAL_MENU : MC_GLOBAL_MENU;
1029
1030 g_free (menu);
1031 menu = mc_build_filename (mc_config_get_home_dir (), global_menu, (char *) NULL);
1032 if (!exist_file (menu))
1033 {
1034 g_free (menu);
1035 menu = mc_build_filename (mc_global.sysconfig_dir, global_menu, (char *) NULL);
1036 if (!exist_file (menu))
1037 {
1038 g_free (menu);
1039 menu = mc_build_filename (mc_global.share_data_dir, global_menu, (char *) NULL);
1040 }
1041 }
1042 }
1043 }
1044
1045 if (!g_file_get_contents (menu, &data, NULL, NULL))
1046 {
1047 message (D_ERROR, MSG_ERROR, _("Cannot open file %s\n%s"), menu, unix_error_string (errno));
1048 MC_PTR_FREE (menu);
1049 return FALSE;
1050 }
1051
1052 old_patterns = easy_patterns;
1053
1054
1055 for (p = check_patterns (data); *p != '\0'; str_next_char (&p))
1056 {
1057 unsigned int menu_lines = entries == NULL ? 0 : entries->len;
1058
1059 if (col == 0 && (entries == NULL || menu_lines == entries->len))
1060 switch (*p)
1061 {
1062 case '#':
1063
1064 if (selected_entry >= 0 && strncmp (p, "#silent", 7) == 0)
1065 interactive = FALSE;
1066
1067 accept_entry = TRUE;
1068 break;
1069
1070 case '+':
1071 if (*(p + 1) == '=')
1072 {
1073
1074 p = test_line (edit_widget, p + 1, &accept_entry);
1075 if (selected == 0 && accept_entry)
1076 selected = menu_lines;
1077 }
1078 else
1079 {
1080
1081 p = test_line (edit_widget, p, &accept_entry);
1082 }
1083 break;
1084
1085 case '=':
1086 if (*(p + 1) == '+')
1087 {
1088
1089 p = test_line (edit_widget, p + 1, &accept_entry);
1090 if (selected == 0 && accept_entry)
1091 selected = menu_lines;
1092 }
1093 else
1094 {
1095
1096 gboolean ok = TRUE;
1097
1098 p = test_line (edit_widget, p, &ok);
1099 if (selected == 0 && ok)
1100 selected = menu_lines;
1101 }
1102 break;
1103
1104 default:
1105 if (!whitespace (*p) && str_isprint (p))
1106 {
1107
1108 if (accept_entry)
1109 {
1110 if (entries == NULL)
1111 entries = g_ptr_array_new ();
1112 g_ptr_array_add (entries, p);
1113 }
1114 else
1115 accept_entry = TRUE;
1116 }
1117 break;
1118 }
1119
1120 if (*p == '\n')
1121 {
1122 if (entries != NULL && entries->len > menu_lines)
1123 accept_entry = TRUE;
1124 max_cols = MAX (max_cols, col);
1125 col = 0;
1126 }
1127 else
1128 {
1129 if (*p == '\t')
1130 *p = ' ';
1131 col++;
1132 }
1133 }
1134
1135 if (entries == NULL)
1136 message (D_ERROR, MSG_ERROR, _("No suitable entries found in %s"), menu);
1137 else
1138 {
1139 if (selected_entry >= 0)
1140 selected = selected_entry;
1141 else
1142 {
1143 Listbox *listbox;
1144 unsigned int i;
1145
1146 max_cols = MIN (MAX (max_cols, col), MAX_ENTRY_LEN);
1147
1148
1149 listbox = listbox_window_new (entries->len, max_cols + 2, _("User menu"),
1150 "[Edit Menu File]");
1151
1152 for (i = 0; i < entries->len; i++)
1153 {
1154 p = g_ptr_array_index (entries, i);
1155 LISTBOX_APPEND_TEXT (listbox, (unsigned char) p[0],
1156 extract_line (p, p + MAX_ENTRY_LEN, NULL), p, FALSE);
1157 }
1158
1159 listbox_set_current (listbox->list, selected);
1160
1161 selected = listbox_run (listbox);
1162 }
1163
1164 if (selected >= 0)
1165 {
1166 execute_menu_command (edit_widget, g_ptr_array_index (entries, selected), interactive);
1167 res = TRUE;
1168 }
1169
1170 g_ptr_array_free (entries, TRUE);
1171
1172 do_refresh ();
1173 }
1174
1175 easy_patterns = old_patterns;
1176 MC_PTR_FREE (menu);
1177 g_free (data);
1178 return res;
1179 }
1180
1181