Ticket #3727: src_filemanager_usermenu.c.diff
File src_filemanager_usermenu.c.diff, 16.6 KB (added by boruch, 8 years ago) |
---|
-
(a) mc-github/src/filemanager/usermenu.c vs. (b) usermenu.c_006
a b 65 65 66 66 #define MAX_ENTRIES 16 67 67 #define MAX_ENTRY_LEN 60 68 68 #define END_OF_STRING '\0' 69 69 /*** file scope type declarations ****************************************************************/ 70 70 71 71 /*** file scope variables ************************************************************************/ … … 84 84 char *s = ss; 85 85 char *e = NULL; 86 86 87 while (*s != '\0')87 while (*s != END_OF_STRING) 88 88 { 89 89 if (*s == '.') 90 90 e = s; … … 93 93 s++; 94 94 } 95 95 if (e != NULL) 96 *e = '\0';96 *e = END_OF_STRING; 97 97 return ss; 98 98 } 99 99 … … 135 135 static char * 136 136 extract_arg (char *p, char *arg, int size) 137 137 { 138 while (*p != '\0'&& (*p == ' ' || *p == '\t' || *p == '\n'))138 while (*p != END_OF_STRING && (*p == ' ' || *p == '\t' || *p == '\n')) 139 139 p++; 140 140 141 141 /* 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') 143 143 { 144 144 char *np; 145 145 … … 151 151 size -= np - p; 152 152 p = np; 153 153 } 154 *arg = '\0';155 if (*p == '\0'|| *p == '\n')154 *arg = END_OF_STRING; 155 if (*p == END_OF_STRING || *p == '\n') 156 156 str_prev_char (&p); 157 157 return p; 158 158 } … … 167 167 int result = 0; /* False by default */ 168 168 mode_t st_mode = panel->dir.list[panel->selected].st.st_mode; 169 169 170 for (; *arg != '\0'; arg++)170 for (; *arg != END_OF_STRING; arg++) 171 171 { 172 172 switch (*arg) 173 173 { … … 316 316 317 317 len = strlen (msg); 318 318 if (len != 0) 319 msg[len - 1] = '\0';319 msg[len - 1] = END_OF_STRING; 320 320 message (D_NORMAL, _("Debug"), "%s", msg); 321 321 322 322 } … … 361 361 char operator; 362 362 363 363 /* Repeat till end of line */ 364 while (*p != '\0'&& *p != '\n')364 while (*p != END_OF_STRING && *p != '\n') 365 365 { 366 366 char *debug_start, *debug_end; 367 367 gboolean condition = TRUE; … … 369 369 /* support quote space .mnu */ 370 370 while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t') 371 371 p++; 372 if (*p == '\0'|| *p == '\n')372 if (*p == END_OF_STRING || *p == '\n') 373 373 break; 374 374 operator = *p++; 375 375 if (*p == '?') … … 380 380 /* support quote space .mnu */ 381 381 while ((*p == ' ' && *(p - 1) != '\\') || *p == '\t') 382 382 p++; 383 if (*p == '\0'|| *p == '\n')383 if (*p == END_OF_STRING || *p == '\n') 384 384 break; 385 385 386 386 debug_start = p; … … 413 413 /* Report debug message */ 414 414 debug_out (NULL, NULL, TRUE); 415 415 416 if (*p == '\0'|| *p == '\n')416 if (*p == END_OF_STRING || *p == '\n') 417 417 str_prev_char (&p); 418 418 return p; 419 419 } 420 420 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 */ 424 447 static void 425 execute_menu_command (const WEdit * edit_widget, const char * commands, gboolean show_prompt)448 execute_menu_command (const WEdit * edit_widget, const char *unparsed_cmd, gboolean show_prompt) 426 449 { 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 */ 431 477 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 */ 432 489 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 434 495 vfs_path_t *file_name_vpath; 435 496 gboolean run_view = FALSE; 436 497 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; 441 500 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 } 443 521 444 if (cmd_file_fd == -1)522 gboolean found_end_of_input (void) 445 523 { 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; 450 544 } 451 cmd_file = fdopen (cmd_file_fd, "w");452 fputs ("#! /bin/sh\n", cmd_file);453 commands++;454 545 455 for (col = 0; *commands != '\0'; commands++)546 void process_input_box (void) 456 547 { 457 if (col == 0) 548 input_box_prompt = lc_prompt; 549 while TRUE 458 550 { 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--; 464 556 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 == '}') 472 560 { 473 *parameter = '\0'; 474 parameter = 561 input_box_reply = 475 562 input_dialog (_("Parameter"), lc_prompt, MC_HISTORY_FM_MENU_EXEC_PARAM, "", 476 563 INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_CD | 477 564 INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_VARIABLES | 478 565 INPUT_COMPLETE_USERNAMES); 479 if ( parameter == NULL || *parameter == '\0')566 if (input_box_reply == NULL || *input_box_reply == END_OF_STRING) 480 567 { 481 568 /* User canceled */ 482 fclose ( cmd_file);569 fclose (parsed_cmd_file); 483 570 mc_unlink (file_name_vpath); 484 571 vfs_path_free (file_name_vpath); 485 return;572 user_abort = TRUE; 486 573 } 487 if (do_quote)574 else if (do_quote) 488 575 { 489 576 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); 493 579 g_free (tmp); 494 580 } 495 581 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; 499 585 } 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--; 502 607 } 503 else if (expand_prefix_found)608 else 504 609 { 505 expand_prefix_found = FALSE; 506 if (g_ascii_isdigit ((gchar) * commands)) 610 if (g_ascii_isdigit ((gchar) * unparsed_cmd)) 507 611 { 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++; 511 615 } 512 if (* commands== '{')513 p arameter = lc_prompt;616 if (*unparsed_cmd == '{') 617 process_input_box (); 514 618 else 515 619 { 516 620 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); 520 623 g_free (text); 521 624 } 522 625 } 523 else524 {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 else536 {537 do_quote = TRUE; /* Default: Quote expanded macro */538 expand_prefix_found = TRUE;539 }540 }541 else542 fputc (*commands, cmd_file);543 }544 626 } 545 fclose (cmd_file); 546 mc_chmod (file_name_vpath, S_IRWXU); 547 if (run_view) 627 628 gboolean macro_substitution (void) 548 629 { 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; 551 642 } 552 else 643 644 void execute_parsed_cmd_file (void) 553 645 { 554 646 /* execute the command indirectly to allow execution even 555 647 * on no-exec filesystems. */ 556 648 char *cmd; 557 558 649 cmd = g_strconcat ("/bin/sh ", vfs_path_as_str (file_name_vpath), (char *) NULL); 559 650 if (!show_prompt) 560 651 { … … 562 653 message (D_ERROR, MSG_ERROR, "%s", _("Error calling program")); 563 654 } 564 655 else 565 {566 656 shell_execute (cmd, EXECUTE_HIDE); 567 }568 657 g_free (cmd); 569 658 } 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 572 693 } 573 694 574 695 /* --------------------------------------------------------------------------------------------- */ … … 636 757 q += 4; 637 758 if (*q == '{') 638 759 { 639 for (q++; *q != '\0'&& *q != '}'; q++)760 for (q++; *q != END_OF_STRING && *q != '}'; q++) 640 761 { 641 762 if (strncmp (q, DEFAULT_CHARSET, 5) == 0) 642 763 { … … 692 813 const char *dots = NULL; 693 814 const char *value; 694 815 695 for (q += 4; *q != '\0'&& *q != '}'; q++)816 for (q += 4; *q != END_OF_STRING && *q != '}'; q++) 696 817 { 697 818 if (*q == ':') 698 819 dots = q + 1; 699 820 } 700 if (*q == '\0')821 if (*q == END_OF_STRING) 701 822 return 0; 702 823 703 824 if (dots == NULL || dots == q + 5) … … 993 1114 /* Parse the menu file */ 994 1115 old_patterns = easy_patterns; 995 1116 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)) 997 1118 { 998 1119 if (menu_lines >= menu_limit) 999 1120 {