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