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