home *** CD-ROM | disk | FTP | other *** search
- /* User Menu implementation
- Copyright (C) 1994 Miguel de Icaza, Janne Kukonlehto
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include <config.h>
- #include <stdio.h>
- #include "tty.h"
- #include <stdlib.h> /* For free() */
- #include "fs.h"
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
-
- #include "mad.h"
- #include "util.h"
- #include "global.h"
- #include "dialog.h"
- #include "color.h"
- #include "dir.h"
- #include "panel.h"
- #include "main.h"
- #include "user.h"
- #include "layout.h"
- #include "../vfs/vfs.h"
-
- /* For the simple listbox manager */
- #include "dlg.h"
- #include "widget.h"
- #include "wtools.h"
-
- #include "view.h" /* for default_* externs */
-
- /* "$Id: user.c,v 1.16 1995/02/21 19:07:28 miguel Exp $" */
-
- #define MAX_ENTRIES 40
- #define MAX_ENTRY_LEN 60
-
- static char *data;
- static char *entries [MAX_ENTRIES];
- static int max_cols;
- static int menu_lines;
- static int debug_flag = 0;
- static int debug_error = 0;
- extern char *search_string (char *, char *);
-
- /* Formats defined:
- %% The % character
- %f The current file (if non-local vfs, file will be copied locally and
- %f will be full path to it).
- %p The current file
- %d The current working directory
- %s "Selected files"; the tagged files if any, otherwise the current file
- %t Tagged files
- %u Tagged files (and they are untagged on return from expand_format)
- %view Runs the commands and pipes standard output to the view command
- if %view is directly followed by '{', a list of keywords
- ascii, hex, nroff, unformated and
-
- If the format letter is in uppercase, it refers to the other panel.
-
- expand_format returns a memory block that must be free()d.
- */
-
- /* Returns how many characters we should advance if %view was found */
- int check_format_view (char *p)
- {
- char *q = p;
- if (!strncmp (p, "view", 4)){
- q += 4;
- if (*q == '{'){
- for (q++;*q && *q != '}';q++){
- if (!strncmp (q, "ascii", 5)){
- default_hex_mode = 0;
- q += 4;
- } else if (!strncmp (q, "hex", 3)){
- default_hex_mode = 1;
- q += 2;
- } else if (!strncmp (q, "nroff", 5)){
- default_nroff_flag = 1;
- q += 4;
- } else if (!strncmp (q, "unformated", 10)){
- default_nroff_flag = 0;
- q += 9;
- }
- }
- if (*q == '}')
- q++;
- }
- return q - p;
- } else
- return 0;
- }
-
- int check_format_cd (char *p)
- {
- if (!strncmp (p, "cd", 2))
- return 3;
- else
- return 0;
- }
-
- /* Check if p has a "^var\{var-name\}" */
- /* Returns the number of skipped characters (zero on not found) */
- /* V will be set to the expanded variable name */
- int check_format_var (char *p, char **v)
- {
- char *q = p;
- char *var_name;
- char *value;
- char *dots;
-
- *v = 0;
- dots = 0;
- if (!strncmp (p, "var{", 4)){
- for (q += 4; *q && *q != '}'; q++){
- if (*q == ':')
- dots = q+1;
- ;
- }
- if (!*q)
- return 0;
-
- if (!dots || dots == q+5){
- message (1,
- " Format error on file Extensions File ",
- !dots ? " The %%var macro does not have a default "
- : " The %%var macros does not have a variable " );
- return 0;
- }
-
- /* Copy the variable name */
- var_name = xmalloc (dots - p, "check_format_var");
- strncpy (var_name, p+4, dots-2 - (p+3));
- var_name [dots-2 - (p+3)] = 0;
-
- value = getenv (var_name);
- if (value){
- *v = strdup (value);
- return q-p;
- }
- free (var_name);
- var_name = xmalloc (q - dots + 1, "check_format_var_2");
- strncpy (var_name, dots, q - dots + 1);
- var_name [q-dots] = 0;
- *v = var_name;
- return q-p;
- }
- return 0;
- }
-
- /* strip file's extension */
- char *strip_ext(char *ss)
- {
- register char *s = ss;
- char *e = NULL;
- while(*s) {
- if(*s == '.') e = s;
- if(*s == PATH_SEP && e) e=NULL; /* '.' in *directory* name */
- s++;
- }
- if(e) *e = 0;
- return ss;
- }
-
- char *expand_format (char c)
- {
- WPanel *panel;
-
- if (c == '%')
- return strdup ("%");
-
- if (c >= 'a')
- panel = current_panel;
- else {
- if (get_other_type () == view_listing){
- panel = other_panel;
- } else
- return strdup ("");
- }
- if (!panel)
- panel = cpanel;
-
- c |= 0x20;
-
- switch (c){
- case 'f':
- case 'p': return strdup (panel->dir.list [panel->selected].fname);
- case 'b':
- return strip_ext(strdup (panel->dir.list [panel->selected].fname));
- case 'd': return strdup (panel->cwd);
- case 's':
- if (!panel->marked)
- return strdup (panel->dir.list [panel->selected].fname);
-
- /* Fall through */
-
- case 't':
- case 'u':
- {
- int length = 2, i;
- char *block;
-
- for (i = 0; i < panel->count; i++)
- if (panel->dir.list [i].f.marked)
- length += strlen (panel->dir.list [i].fname) + 1;
-
- block = xmalloc (length, "expand_format");
- *block = 0;
- for (i = 0; i < panel->count; i++)
- if (panel->dir.list [i].f.marked){
- strcat (block, panel->dir.list [i].fname);
- strcat (block, " ");
- if (c == 'u')
- file_mark (panel, i, 0);
- }
- if (c == 'u'){
- panel->marked = 0;
- panel->total = 0;
- panel->dirs_marked = 0;
- }
- return block;
- } /* sub case block */
- } /* switch */
- return strdup ("");
- }
-
- /* Checks for shell patterns defination */
- char *check_patterns (char *p)
- {
- const char *def_name = "shell_patterns=";
- int value;
-
- if (strncmp (p, def_name, sizeof (def_name)) == 0){
- p += strlen (def_name);
- value = *p++ - '0';
- if (value == 0 || value == 1)
- easy_patterns = value;
- else
- message (1, " Error ", " Invalid shell pattern defination \"%c\". ", value + '0');
- }
- while (*p == '\n' || *p == '\t' || *p == ' ') p++;
- return p;
- }
-
- /* Copies a whitespace separated argument from p to arg. Returns the
- point after argument. */
- static char *extract_arg (char *p, char *arg)
- {
- while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
- p++;
- while (*p && *p != ' ' && *p != '\t' && *p != '\n')
- *arg++ = *p++;
- *arg = 0;
- if (!*p || *p == '\n')
- p --;
- return p;
- }
-
- /* Tests whether the selected file in the panel is of any of the types
- specified in argument. */
- static int test_type (WPanel *panel, char *arg)
- {
- int result = 0; /* False by default */
- int st_mode = panel->dir.list [panel->selected].buf.st_mode;
-
- for (;*arg != 0; arg++){
- switch (*arg){
- case 'n': /* Not a directory */
- result |= !S_ISDIR (st_mode);
- break;
- case 'r': /* Regular file */
- result |= S_ISREG (st_mode);
- break;
- case 'd': /* Directory */
- result |= S_ISDIR (st_mode);
- break;
- case 'l': /* Link */
- result |= S_ISLNK (st_mode);
- break;
- case 'c': /* Character special */
- result |= S_ISCHR (st_mode);
- break;
- case 'b': /* Block special */
- result |= S_ISBLK (st_mode);
- break;
- case 'f': /* Fifo (named pipe) */
- result |= S_ISFIFO (st_mode);
- break;
- case 's': /* Socket */
- result |= S_ISSOCK (st_mode);
- break;
- case 'x': /* Executable */
- result |= (st_mode & 0111) ? 1 : 0;
- break;
- case 't':
- result |= panel->marked ? 1 : 0;
- break;
- default:
- debug_error = 1;
- break;
- }
- }
- return result;
- }
-
- /* Calculates the truth value of the next condition starting from
- p. Returns the point after condition. */
- static char *test_condition (char *p, int *condition)
- {
- WPanel *panel;
- char arg [256];
-
- /* Handle one condition */
- for (;*p != '\n' && *p != '&' && *p != '|'; p++){
- if (*p == ' ' || *p == '\t')
- continue;
- if (*p >= 'a')
- panel = current_panel;
- else {
- if (get_other_type () == view_listing)
- panel = other_panel;
- else
- panel = NULL;
- }
- *p |= 0x20;
-
- switch (*p++){
- case '!':
- p = test_condition (p, condition);
- *condition = ! *condition;
- p--;
- break;
- case 'f':
- p = extract_arg (p, arg);
- *condition = panel && regexp_match (arg, panel->dir.list [panel->selected].fname, match_file);
- break;
- case 'd':
- p = extract_arg (p, arg);
- *condition = panel && regexp_match (arg, panel->cwd, match_file);
- break;
- case 't':
- p = extract_arg (p, arg);
- *condition = panel && test_type (panel, arg);
- break;
- default:
- debug_error = 1;
- break;
- } /* switch */
-
- } /* while */
- return p;
- }
-
- /* General purpose condition debug output handler */
- void debug_out (char *start, char *end, int cond)
- {
- static char msg [256];
- int len;
-
- if (start == NULL && end == NULL){
- if (cond == 0){
- /* Init */
- msg [0] = 0;
- } else {
- /* Show output */
- if (!debug_flag)
- return;
- len = strlen (msg);
- if (len)
- msg [len - 1] = 0;
- message (0, " Debug ", msg);
- debug_flag = 0;
- }
- } else {
- /* Save debug info for later output */
- if (!debug_flag)
- return;
- /* Save the result of the condition */
- if (debug_error){
- strcat (msg, " ERROR: ");
- debug_error = 0;
- }
- else if (cond)
- strcat (msg, " True: ");
- else
- strcat (msg, " False: ");
- /* Copy condition statement */
- len = strlen (msg);
- if (end == NULL){
- /* Copy one character */
- msg [len] = *start;
- msg [len + 1] = 0;
- } else {
- /* Copy many characters */
- while (start < end){
- msg [len++] = *start++;
- }
- msg [len] = 0;
- }
- strcat (msg, " \n");
- }
- }
-
- /* Calculates the truth value of one lineful of conditions. Returns
- the point just before the end of line. */
- static char *test_line (char *p, int *result)
- {
- int condition;
- char operator;
- char *debug_start, *debug_end;
-
- /* Init debugger */
- debug_out (NULL, NULL, 0);
- /* Repeat till end of line */
- while (*p && *p != '\n'){
- while (*p == ' ' || *p == '\t')
- p++;
- if (!*p || *p == '\n')
- break;
- operator = *p++;
- if (*p == '?'){
- debug_flag = 1;
- p++;
- }
- while (*p == ' ' || *p == '\t')
- p++;
- if (!*p || *p == '\n')
- break;
- condition = 1; /* True by default */
-
- debug_start = p;
- p = test_condition (p, &condition);
- debug_end = p;
- /* Add one debug statement */
- debug_out (debug_start, debug_end, condition);
-
- switch (operator){
- case '+':
- case '=':
- /* Assignment */
- *result = condition;
- break;
- case '&': /* Logical and */
- *result &= condition;
- break;
- case '|': /* Logical or */
- *result |= condition;
- break;
- default:
- debug_error = 1;
- break;
- } /* switch */
- /* Add one debug statement */
- debug_out (&operator, NULL, *result);
-
- } /* while (*p != '\n') */
- /* Report debug message */
- debug_out (NULL, NULL, 1);
-
- if (!*p || *p == '\n')
- p --;
- return p;
- }
-
- /* FIXME: recode this routine on version 3.0, it could be cleaner */
- void execute_menu_command (char *s)
- {
- char *commands;
- FILE *cmd_file;
- int expand_prefix_found = 0;
- int parameter_found = 0;
- char prompt [80] = "";
- int col;
- char *file_name = tmpnam (0);
-
- #ifdef _OS_NT
- /* NT requires the command to end in .cmd */
- file_name = copy_strings (file_name, ".cmd", NULL);
- #endif
- if ((cmd_file = fopen (file_name, "w+")) == NULL){
- message (1, " Error ", " Can't create temporary command file \n %s ",
- unix_error_string (errno));
- return;
- }
- commands = strchr (s, '\n');
- if (!commands){
- fclose (cmd_file);
- unlink (file_name);
- return;
- }
- commands++;
-
- for (col = 0; *commands; commands++){
- if (col == 0 && (*commands != ' ' && *commands != '\t'))
- break;
- else if (col == 0)
- while (*commands == ' ' || *commands == '\t')
- commands++;
- col++;
- if (*commands == '\n')
- col = 0;
- if (parameter_found){
- if (*commands == '}'){
- char *parameter;
- parameter_found = 0;
- parameter = input_dialog (" Parameter ", prompt, "");
- if (!parameter || !*parameter){
- /* User canceled */
- fclose (cmd_file);
- unlink (file_name);
- return;
- }
- fputs (parameter, cmd_file);
- free (parameter);
- } else {
- int len = strlen (prompt);
-
- if (len+1 < sizeof (prompt)){
- prompt [len] = *commands;
- prompt [len+1] = 0;
- } else
- prompt [sizeof (prompt)] = 0;
- }
- } else if (expand_prefix_found){
- expand_prefix_found = 0;
- if (*commands == '{')
- parameter_found = 1;
- else{
- char *text = expand_format (*commands);
- fputs (text, cmd_file);
- free (text);
- }
- } else {
- if (*commands == '%')
- expand_prefix_found = 1;
- else
- fputc (*commands, cmd_file);
- }
- }
- fclose (cmd_file);
- chmod (file_name, S_IRWXU);
- execute (file_name);
- unlink (file_name);
- }
-
- void user_menu_cmd (void)
- {
- char *menu, *p;
- int col, i, accept_entry = 1;
- int selected, old_patterns;
- Listbox *listbox;
-
- if (!vfs_current_is_local ()){
- message (1, " Oops... ",
- " I can't run programs while logged on a non local directory ");
- return;
- }
-
- menu = copy_strings (home_dir, PATH_SEP_STR ".mc.menu", 0);
- if (!exist_file (menu)){
- free (menu);
- menu = copy_strings (LIBDIR, "mc.menu", 0);
- }
-
- if ((data = load_file (menu)) == NULL){
- message (1, " Error ", " Can't open file %s \n %s ",
- menu, unix_error_string (errno));
- free (menu);
- return;
- }
- free (menu);
-
- max_cols = 0;
- for (i = 0; i < MAX_ENTRIES; i++)
- entries [i] = 0;
- selected = 0;
-
- /* Parse the menu file */
- old_patterns = easy_patterns;
- p = check_patterns (data);
- for (menu_lines = col = 0; *p; p++){
- if (col == 0 && !entries [menu_lines]){
- if (*p == '#'){
- /* A commented menu entry */
- accept_entry = 1;
- } else if (*p == '+'){
- if (*(p+1) == '='){
- /* Combined adding and default */
- p = test_line (++p, &accept_entry);
- if (selected == 0 && accept_entry)
- selected = menu_lines;
- } else {
- /* A condition for adding the entry */
- p = test_line (p, &accept_entry);
- }
- } else if (*p == '='){
- if (*(p+1) == '+'){
- /* Combined adding and default */
- p = test_line (++p, &accept_entry);
- if (selected == 0 && accept_entry)
- selected = menu_lines;
- } else {
- /* A condition for making the entry default */
- i = 1;
- p = test_line (p, &i);
- if (selected == 0 && i)
- selected = menu_lines;
- }
- }
- else if (*p > ' ' && *p < 127){
- /* A menu entry title line */
- if (accept_entry)
- entries [menu_lines] = p;
- else
- accept_entry = 1;
- }
- }
- if (menu_lines == MAX_ENTRIES)
- break;
- if (*p == '\t')
- *p = ' ';
- col++;
- if (*p == '\n'){
- if (entries [menu_lines]){
- menu_lines++;
- accept_entry = 1;
- }
- max_cols = max (max_cols, col);
- col = 0;
- }
- }
- max_cols = min (max (max_cols, col), MAX_ENTRY_LEN);
-
- /* Create listbox */
- listbox = create_listbox_window (max_cols+2, menu_lines, " User menu ",
- "[Menu File Edit]");
-
- /* insert all the items found */
- for (i = 0; i < menu_lines; i++)
- LISTBOX_APPEND_TEXT (listbox, entries [i][0],
- extract_line (entries [i],
- entries [i]+MAX_ENTRY_LEN),
- entries [i]);
-
- /* Select the default entry */
- listbox_select_by_number (listbox->list, selected);
-
- selected = run_listbox (listbox);
- if (selected >= 0)
- execute_menu_command (entries [selected]);
-
- easy_patterns = old_patterns;
- do_refresh ();
- free (data);
- }
-