Ticket #3727: src_filemanager_usermenu.c.diff

File src_filemanager_usermenu.c.diff, 16.6 KB (added by boruch, 5 years ago)
  • (a) mc-github/src/filemanager/usermenu.c vs. (b) usermenu.c_006

    a b  
    6565 
    6666#define MAX_ENTRIES 16 
    6767#define MAX_ENTRY_LEN 60 
    68  
     68#define END_OF_STRING '\0' 
    6969/*** file scope type declarations ****************************************************************/ 
    7070 
    7171/*** file scope variables ************************************************************************/ 
     
    8484    char *s = ss; 
    8585    char *e = NULL; 
    8686 
    87     while (*s != '\0') 
     87    while (*s != END_OF_STRING) 
    8888    { 
    8989        if (*s == '.') 
    9090            e = s; 
     
    9393        s++; 
    9494    } 
    9595    if (e != NULL) 
    96         *e = '\0'; 
     96        *e = END_OF_STRING; 
    9797    return ss; 
    9898} 
    9999 
     
    135135static char * 
    136136extract_arg (char *p, char *arg, int size) 
    137137{ 
    138     while (*p != '\0' && (*p == ' ' || *p == '\t' || *p == '\n')) 
     138    while (*p != END_OF_STRING && (*p == ' ' || *p == '\t' || *p == '\n')) 
    139139        p++; 
    140140 
    141141    /* support quote space .mnu */ 
    142     while (*p != '\0' && (*p != ' ' || *(p - 1) == '\\') && *p != '\t' && *p != '\n') 
     142    while (*p != END_OF_STRING && (*p != ' ' || *(p - 1) == '\\') && *p != '\t' && *p != '\n') 
    143143    { 
    144144        char *np; 
    145145 
     
    151151        size -= np - p; 
    152152        p = np; 
    153153    } 
    154     *arg = '\0'; 
    155     if (*p == '\0' || *p == '\n') 
     154    *arg = END_OF_STRING; 
     155    if (*p == END_OF_STRING || *p == '\n') 
    156156        str_prev_char (&p); 
    157157    return p; 
    158158} 
     
    167167    int result = 0;             /* False by default */ 
    168168    mode_t st_mode = panel->dir.list[panel->selected].st.st_mode; 
    169169 
    170     for (; *arg != '\0'; arg++) 
     170    for (; *arg != END_OF_STRING; arg++) 
    171171    { 
    172172        switch (*arg) 
    173173        { 
     
    316316 
    317317            len = strlen (msg); 
    318318            if (len != 0) 
    319                 msg[len - 1] = '\0'; 
     319                msg[len - 1] = END_OF_STRING; 
    320320            message (D_NORMAL, _("Debug"), "%s", msg); 
    321321 
    322322        } 
     
    361361    char operator; 
    362362 
    363363    /* Repeat till end of line */ 
    364     while (*p != '\0' && *p != '\n') 
     364    while (*p != END_OF_STRING && *p != '\n') 
    365365    { 
    366366        char *debug_start, *debug_end; 
    367367        gboolean condition = TRUE; 
     
    369369        /* support quote space .mnu */ 
    370370        while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t') 
    371371            p++; 
    372         if (*p == '\0' || *p == '\n') 
     372        if (*p == END_OF_STRING || *p == '\n') 
    373373            break; 
    374374        operator = *p++; 
    375375        if (*p == '?') 
     
    380380        /* support quote space .mnu */ 
    381381        while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t') 
    382382            p++; 
    383         if (*p == '\0' || *p == '\n') 
     383        if (*p == END_OF_STRING || *p == '\n') 
    384384            break; 
    385385 
    386386        debug_start = p; 
     
    413413    /* Report debug message */ 
    414414    debug_out (NULL, NULL, TRUE); 
    415415 
    416     if (*p == '\0' || *p == '\n') 
     416    if (*p == END_OF_STRING || *p == '\n') 
    417417        str_prev_char (&p); 
    418418    return p; 
    419419} 
    420420 
    421 /* --------------------------------------------------------------------------------------------- */ 
    422 /** FIXME: recode this routine on version 3.0, it could be cleaner */ 
    423  
     421/* 
     422 * execute_menu_command: 
     423 *  
     424 *   DESCRIPTION: 
     425 *     Parses a menu command byte-by-byte, performs all macro 
     426 *     substitutions, and attempts to execute the result as a 
     427 *     shell script (/bin/sh, not /bin/bash). 
     428 * 
     429 *   PARAMETERS: 
     430 *     edit_widget: 
     431 *     unparsed_cmd: the text of the menu entry, from its title 
     432 *       line until its termination. 
     433 *     show_prompt: 
     434 * 
     435 *   This function begins with several (temporary) embedded 
     436 *   sub-functions: 
     437 *     prepare_output_parsed_cmd_file () 
     438 *     found_end_of_input () 
     439 *     macro_substitution() 
     440 *     macro_substition_completion() 
     441 *     process_input_box() 
     442 *     execute_parsed_cmd_file() 
     443 *     main_execute_menu_command() 
     444 *   The processing begins with the call to sub-function 
     445 *   main_execute_menu_command. 
     446 */ 
    424447static void 
    425 execute_menu_command (const WEdit * edit_widget, const char *commands, gboolean show_prompt) 
     448execute_menu_command (const WEdit * edit_widget, const char *unparsed_cmd, gboolean show_prompt) 
    426449{ 
    427     FILE *cmd_file; 
    428     int cmd_file_fd; 
    429     gboolean expand_prefix_found = FALSE; 
    430     char *parameter = NULL; 
     450    /* 
     451     * These next three variables support the user menu macro 
     452     * %{some text}, which indicates to mc to create an ncurses- 
     453     * style input dialog, using "some text" as the prompt. 
     454     * 
     455     * input_box_prompt: an incrementing pointer within the static 
     456     *        array "lc_prompt" (defined below) to place there the 
     457     *        input prompt "some_text". 
     458     * 
     459     * input_box_reply: pointer to a dynamically allocated buffer 
     460     *        holding the user's ersponse to the input dialog. The 
     461     *        function will add the response to the parsed command 
     462     *        which will be executed at the successful conclusion of 
     463     *        this function. 
     464     * 
     465     * user_abort: respect a user's response to the input_box. 
     466     */ 
     467    char *input_box_prompt = NULL; 
     468    char *input_box_reply = NULL; 
     469    gboolean user_abort = FALSE; 
     470    /* 
     471     * do_quote: "%0" indicate not to surround the following macro 
     472     *     substition in quotes. When the macro prefix character is 
     473     *     followed by any other digit, the indication is to quote 
     474     *     the substitution, ie. "%0f" will potentially substitute 
     475     *     unquoted a file name with embedded spaces. 
     476     */ 
    431477    gboolean do_quote = FALSE; 
     478    /* 
     479     * lc_prompt: This static array will hold a prompt "some_text" 
     480     *     to be displayed to a user in an ncurses-style input 
     481     *     dialog box for any occurrence of the macro "%{some_text}" 
     482     * 
     483     * WISHLIST: convert it to a resizable and dynamically allocated 
     484     *     buffer. I want this because I would like to be able to 
     485     *     present the user with longer and multi-line prompt 
     486     *     strings. This would also separately require modifications 
     487     *     to the widget function wrapped by function "input_dialog". 
     488     */ 
    432489    char lc_prompt[80]; 
    433     int col; 
     490    /* line_begin: menu command lines must begin with whitespace 
     491     *     (ie. space or tab). 
     492     */ 
     493    gboolean line_begin = TRUE; 
     494 
    434495    vfs_path_t *file_name_vpath; 
    435496    gboolean run_view = FALSE; 
    436497 
    437     /* Skip menu entry title line */ 
    438     commands = strchr (commands, '\n'); 
    439     if (commands == NULL) 
    440         return; 
     498    FILE *parsed_cmd_file; 
     499    int parsed_cmd_file_fd; 
    441500 
    442     cmd_file_fd = mc_mkstemps (&file_name_vpath, "mcusr", SCRIPT_SUFFIX); 
     501    /* BEGIN SUB-FUNCTIONS */ 
     502    /* 
     503     *  I suggest that this function be moved to its own source 
     504     *  code file for clarity / readability. 
     505     */ 
     506    gboolean prepare_output_parsed_cmd_file (void) 
     507    { 
     508        parsed_cmd_file_fd = mc_mkstemps (&file_name_vpath, "mcusr", SCRIPT_SUFFIX); 
     509        if (parsed_cmd_file_fd == -1) 
     510        { 
     511            message (D_ERROR, MSG_ERROR, _("Cannot create temporary command file\n%s"), 
     512                     unix_error_string (errno)); 
     513            vfs_path_free (file_name_vpath); 
     514            return FALSE; 
     515        } 
     516        parsed_cmd_file = fdopen (parsed_cmd_file_fd, "w"); 
     517        fputs ("#! /bin/sh\n", parsed_cmd_file); 
     518        unparsed_cmd++; 
     519        return TRUE; 
     520    } 
    443521 
    444     if (cmd_file_fd == -1) 
     522    gboolean found_end_of_input (void) 
    445523    { 
    446         message (D_ERROR, MSG_ERROR, _("Cannot create temporary command file\n%s"), 
    447                  unix_error_string (errno)); 
    448         vfs_path_free (file_name_vpath); 
    449         return; 
     524        /* 
     525         *  return TRUE if we find any indication of an end to 
     526         *  parsing, ie. an empty line or a line not beginning 
     527         *  with whitespace. The other EOF condition, END_OF_STRING, 
     528         *  was checked in the 'for' loop statement wrapping this 
     529         *  function. 
     530         */ 
     531        if (line_begin) 
     532        { 
     533            if (*unparsed_cmd != ' ' && *unparsed_cmd != '\t') 
     534                return TRUE; 
     535            while (*unparsed_cmd == ' ' || *unparsed_cmd == '\t') 
     536                unparsed_cmd++; 
     537            if (*unparsed_cmd == '\n') 
     538                return TRUE; 
     539        } 
     540        if (*unparsed_cmd == END_OF_STRING) 
     541            return TRUE; 
     542        line_begin = FALSE; 
     543        return FALSE; 
    450544    } 
    451     cmd_file = fdopen (cmd_file_fd, "w"); 
    452     fputs ("#! /bin/sh\n", cmd_file); 
    453     commands++; 
    454545 
    455     for (col = 0; *commands != '\0'; commands++) 
     546    void process_input_box (void) 
    456547    { 
    457         if (col == 0) 
     548        input_box_prompt = lc_prompt; 
     549        while TRUE 
    458550        { 
    459             if (*commands != ' ' && *commands != '\t') 
    460                 break; 
    461             while (*commands == ' ' || *commands == '\t') 
    462                 commands++; 
    463             if (*commands == '\0') 
     551            unparsed_cmd++; 
     552            if (found_end_of_input ()) 
     553            { 
     554                /* unexpected EOF. rewind and let main function handle it */ 
     555                unparsed_cmd--; 
    464556                break; 
    465         } 
    466         col++; 
    467         if (*commands == '\n') 
    468             col = 0; 
    469         if (parameter != NULL) 
    470         { 
    471             if (*commands == '}') 
     557            } 
     558            /* if reached end of input prompt string */ 
     559            if (*unparsed_cmd == '}') 
    472560            { 
    473                 *parameter = '\0'; 
    474                 parameter = 
     561                input_box_reply = 
    475562                    input_dialog (_("Parameter"), lc_prompt, MC_HISTORY_FM_MENU_EXEC_PARAM, "", 
    476563                                  INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD | 
    477564                                  INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_VARIABLES | 
    478565                                  INPUT_COMPLETE_USERNAMES); 
    479                 if (parameter == NULL || *parameter == '\0') 
     566                if (input_box_reply == NULL || *input_box_reply == END_OF_STRING) 
    480567                { 
    481568                    /* User canceled */ 
    482                     fclose (cmd_file); 
     569                    fclose (parsed_cmd_file); 
    483570                    mc_unlink (file_name_vpath); 
    484571                    vfs_path_free (file_name_vpath); 
    485                     return; 
     572                    user_abort = TRUE; 
    486573                } 
    487                 if (do_quote) 
     574                else if (do_quote) 
    488575                { 
    489576                    char *tmp; 
    490  
    491                     tmp = name_quote (parameter, FALSE); 
    492                     fputs (tmp, cmd_file); 
     577                    tmp = name_quote (input_box_reply, FALSE); 
     578                    fputs (tmp, parsed_cmd_file); 
    493579                    g_free (tmp); 
    494580                } 
    495581                else 
    496                     fputs (parameter, cmd_file); 
    497  
    498                 MC_PTR_FREE (parameter); 
     582                    fputs (input_box_reply, parsed_cmd_file); 
     583                MC_PTR_FREE (input_box_reply); 
     584                break; 
    499585            } 
    500             else if (parameter < lc_prompt + sizeof (lc_prompt) - 1) 
    501                 *parameter++ = *commands; 
     586            /* 
     587             * add another character of macro %{some_text} to the 
     588             * static 80 character buffer that began at location 
     589             * lc_prompt if there is space remaining there. Variable 
     590             * "unparsed_cmd" points to the next character to parse in 
     591             * the menu entry. 
     592             */ 
     593            else if (input_box_prompt < lc_prompt + sizeof (lc_prompt) - 1) 
     594                *input_box_prompt++ = *unparsed_cmd; 
     595        } 
     596    } 
     597 
     598    void macro_substitution_completion (void) 
     599    { 
     600        /* Quote expanded macro unless next char is zero */ 
     601        do_quote = TRUE; 
     602        unparsed_cmd++; 
     603        if (found_end_of_input ()) 
     604        { 
     605            /* unexpected EOF. rewind and let main function handle it */ 
     606            unparsed_cmd--; 
    502607        } 
    503         else if (expand_prefix_found) 
     608        else 
    504609        { 
    505             expand_prefix_found = FALSE; 
    506             if (g_ascii_isdigit ((gchar) * commands)) 
     610            if (g_ascii_isdigit ((gchar) * unparsed_cmd)) 
    507611            { 
    508                 do_quote = (atoi (commands) != 0); 
    509                 while (g_ascii_isdigit ((gchar) * commands)) 
    510                     commands++; 
     612                do_quote = (atoi (unparsed_cmd) != 0); 
     613                while (g_ascii_isdigit ((gchar) * unparsed_cmd)) 
     614                    unparsed_cmd++; 
    511615            } 
    512             if (*commands == '{') 
    513                 parameter = lc_prompt; 
     616            if (*unparsed_cmd == '{') 
     617                process_input_box (); 
    514618            else 
    515619            { 
    516620                char *text; 
    517  
    518                 text = expand_format (edit_widget, *commands, do_quote); 
    519                 fputs (text, cmd_file); 
     621                text = expand_format (edit_widget, *unparsed_cmd, do_quote); 
     622                fputs (text, parsed_cmd_file); 
    520623                g_free (text); 
    521624            } 
    522625        } 
    523         else 
    524         { 
    525             if (*commands == '%') 
    526             { 
    527                 int i; 
    528  
    529                 i = check_format_view (commands + 1); 
    530                 if (i != 0) 
    531                 { 
    532                     commands += i; 
    533                     run_view = TRUE; 
    534                 } 
    535                 else 
    536                 { 
    537                     do_quote = TRUE;    /* Default: Quote expanded macro */ 
    538                     expand_prefix_found = TRUE; 
    539                 } 
    540             } 
    541             else 
    542                 fputc (*commands, cmd_file); 
    543         } 
    544626    } 
    545     fclose (cmd_file); 
    546     mc_chmod (file_name_vpath, S_IRWXU); 
    547     if (run_view) 
     627 
     628    gboolean macro_substitution (void) 
    548629    { 
    549         mcview_viewer (vfs_path_as_str (file_name_vpath), NULL, 0, 0, 0); 
    550         dialog_switch_process_pending (); 
     630        int len; 
     631        if (*unparsed_cmd != '%') 
     632            return FALSE; 
     633        len = check_format_view (unparsed_cmd + 1); 
     634        if (len != 0) 
     635        { 
     636            unparsed_cmd += len; 
     637            run_view = TRUE; 
     638        } 
     639        else 
     640            macro_substitution_completion (); 
     641        return TRUE; 
    551642    } 
    552     else 
     643 
     644    void execute_parsed_cmd_file (void) 
    553645    { 
    554646        /* execute the command indirectly to allow execution even 
    555647         * on no-exec filesystems. */ 
    556648        char *cmd; 
    557  
    558649        cmd = g_strconcat ("/bin/sh ", vfs_path_as_str (file_name_vpath), (char *) NULL); 
    559650        if (!show_prompt) 
    560651        { 
     
    562653                message (D_ERROR, MSG_ERROR, "%s", _("Error calling program")); 
    563654        } 
    564655        else 
    565         { 
    566656            shell_execute (cmd, EXECUTE_HIDE); 
    567         } 
    568657        g_free (cmd); 
    569658    } 
    570     mc_unlink (file_name_vpath); 
    571     vfs_path_free (file_name_vpath); 
     659 
     660    void main_execute_menu_command (void) 
     661    { 
     662        /* Skip menu entry title line */ 
     663        unparsed_cmd = strchr (unparsed_cmd, '\n'); 
     664        if (unparsed_cmd == NULL) 
     665            /* menu entry was a title with no executable code! */ 
     666            return; 
     667        if (!prepare_output_parsed_cmd_file ()) 
     668            return; 
     669        for (; !found_end_of_input (); unparsed_cmd++) 
     670        { 
     671            if (!macro_substitution ()) 
     672                fputc (*unparsed_cmd, parsed_cmd_file); 
     673            else if (user_abort) 
     674                /* user aborted at an input dialog box, eg. C-c, ESC */ 
     675                return; 
     676        } 
     677        fclose (parsed_cmd_file); 
     678        mc_chmod (file_name_vpath, S_IRWXU); 
     679        if (run_view) 
     680        { 
     681            mcview_viewer (vfs_path_as_str (file_name_vpath), NULL, 0, 0, 0); 
     682            dialog_switch_process_pending (); 
     683        } 
     684        else 
     685            execute_parsed_cmd_file (); 
     686        mc_unlink (file_name_vpath); 
     687        vfs_path_free (file_name_vpath); 
     688    } 
     689    /* END SUB-FUNCTIONS */ 
     690 
     691    main_execute_menu_command (); 
     692 
    572693} 
    573694 
    574695/* --------------------------------------------------------------------------------------------- */ 
     
    636757        q += 4; 
    637758        if (*q == '{') 
    638759        { 
    639             for (q++; *q != '\0' && *q != '}'; q++) 
     760            for (q++; *q != END_OF_STRING && *q != '}'; q++) 
    640761            { 
    641762                if (strncmp (q, DEFAULT_CHARSET, 5) == 0) 
    642763                { 
     
    692813        const char *dots = NULL; 
    693814        const char *value; 
    694815 
    695         for (q += 4; *q != '\0' && *q != '}'; q++) 
     816        for (q += 4; *q != END_OF_STRING && *q != '}'; q++) 
    696817        { 
    697818            if (*q == ':') 
    698819                dots = q + 1; 
    699820        } 
    700         if (*q == '\0') 
     821        if (*q == END_OF_STRING) 
    701822            return 0; 
    702823 
    703824        if (dots == NULL || dots == q + 5) 
     
    9931114    /* Parse the menu file */ 
    9941115    old_patterns = easy_patterns; 
    9951116    p = check_patterns (data); 
    996     for (menu_lines = col = 0; *p != '\0'; str_next_char (&p)) 
     1117    for (menu_lines = col = 0; *p != END_OF_STRING; str_next_char (&p)) 
    9971118    { 
    9981119        if (menu_lines >= menu_limit) 
    9991120        {