root/src/filemanager/ext.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. exec_cleanup_script
  2. exec_cleanup_file_name
  3. exec_get_file_name
  4. exec_expand_format
  5. exec_get_export_variables
  6. exec_make_shell_string
  7. exec_extension_view
  8. exec_extension_cd
  9. exec_extension
  10. get_popen_information
  11. get_file_type_local
  12. get_file_encoding_local
  13. regex_check_type
  14. flush_extension_file
  15. regex_command_for

   1 /*
   2    Extension dependent execution.
   3 
   4    Copyright (C) 1994-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Jakub Jelinek, 1995
   9    Miguel de Icaza, 1994
  10    Slava Zanko <slavazanko@gmail.com>, 2013
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file  ext.c
  29  *  \brief Source: extension dependent execution
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <ctype.h>
  35 #include <errno.h>
  36 #include <stdlib.h>
  37 #include <stdio.h>
  38 #include <string.h>
  39 #include <unistd.h>
  40 
  41 #include "lib/global.h"
  42 #include "lib/tty/tty.h"
  43 #include "lib/search.h"
  44 #include "lib/fileloc.h"
  45 #include "lib/mcconfig.h"
  46 #include "lib/util.h"
  47 #include "lib/vfs/vfs.h"
  48 #include "lib/widget.h"
  49 #ifdef HAVE_CHARSET
  50 #include "lib/charsets.h"       /* get_codepage_index */
  51 #endif
  52 
  53 #include "src/setup.h"          /* use_file_to_check_type */
  54 #include "src/execute.h"
  55 #include "src/history.h"
  56 #include "src/usermenu.h"
  57 
  58 #include "src/consaver/cons.saver.h"
  59 #include "src/viewer/mcviewer.h"
  60 
  61 #ifdef HAVE_CHARSET
  62 #include "src/selcodepage.h"    /* do_set_codepage */
  63 #endif
  64 
  65 #include "filemanager.h"        /* current_panel */
  66 #include "panel.h"              /* panel_cd */
  67 
  68 #include "ext.h"
  69 
  70 /*** global variables ****************************************************************************/
  71 
  72 /*** file scope macro definitions ****************************************************************/
  73 
  74 #ifdef FILE_L
  75 #define FILE_CMD "file -L -z "
  76 #else
  77 #define FILE_CMD "file -z "
  78 #endif
  79 
  80 /*** file scope type declarations ****************************************************************/
  81 
  82 typedef char *(*quote_func_t) (const char *name, gboolean quote_percent);
  83 
  84 /*** file scope variables ************************************************************************/
  85 
  86 /* This variable points to a copy of the mc.ext file in memory
  87  * With this we avoid loading/parsing the file each time we
  88  * need it
  89  */
  90 static char *data = NULL;
  91 static vfs_path_t *localfilecopy_vpath = NULL;
  92 static char buffer[BUF_1K];
  93 
  94 static char *pbuffer = NULL;
  95 static time_t localmtime = 0;
  96 static quote_func_t quote_func = name_quote;
  97 static gboolean run_view = FALSE;
  98 static gboolean is_cd = FALSE;
  99 static gboolean written_nonspace = FALSE;
 100 static gboolean do_local_copy = FALSE;
 101 
 102 /* --------------------------------------------------------------------------------------------- */
 103 /*** file scope functions ************************************************************************/
 104 /* --------------------------------------------------------------------------------------------- */
 105 
 106 static void
 107 exec_cleanup_script (vfs_path_t * script_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 108 {
 109     if (script_vpath != NULL)
 110     {
 111         (void) mc_unlink (script_vpath);
 112         vfs_path_free (script_vpath);
 113     }
 114 }
 115 
 116 /* --------------------------------------------------------------------------------------------- */
 117 
 118 static void
 119 exec_cleanup_file_name (const vfs_path_t * filename_vpath, gboolean has_changed)
     /* [previous][next][first][last][top][bottom][index][help]  */
 120 {
 121     if (localfilecopy_vpath == NULL)
 122         return;
 123 
 124     if (has_changed)
 125     {
 126         struct stat mystat;
 127 
 128         mc_stat (localfilecopy_vpath, &mystat);
 129         has_changed = localmtime != mystat.st_mtime;
 130     }
 131     mc_ungetlocalcopy (filename_vpath, localfilecopy_vpath, has_changed);
 132     vfs_path_free (localfilecopy_vpath);
 133     localfilecopy_vpath = NULL;
 134 }
 135 
 136 /* --------------------------------------------------------------------------------------------- */
 137 
 138 static char *
 139 exec_get_file_name (const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 140 {
 141     if (!do_local_copy)
 142         return quote_func (vfs_path_get_last_path_str (filename_vpath), FALSE);
 143 
 144     if (localfilecopy_vpath == NULL)
 145     {
 146         struct stat mystat;
 147         localfilecopy_vpath = mc_getlocalcopy (filename_vpath);
 148         if (localfilecopy_vpath == NULL)
 149             return NULL;
 150 
 151         mc_stat (localfilecopy_vpath, &mystat);
 152         localmtime = mystat.st_mtime;
 153     }
 154 
 155     return quote_func (vfs_path_get_last_path_str (localfilecopy_vpath), FALSE);
 156 }
 157 
 158 /* --------------------------------------------------------------------------------------------- */
 159 
 160 static char *
 161 exec_expand_format (char symbol, gboolean is_result_quoted)
     /* [previous][next][first][last][top][bottom][index][help]  */
 162 {
 163     char *text;
 164 
 165     text = expand_format (NULL, symbol, TRUE);
 166     if (is_result_quoted && text != NULL)
 167     {
 168         char *quoted_text;
 169 
 170         quoted_text = g_strdup_printf ("\"%s\"", text);
 171         g_free (text);
 172         text = quoted_text;
 173     }
 174     return text;
 175 }
 176 
 177 /* --------------------------------------------------------------------------------------------- */
 178 
 179 static GString *
 180 exec_get_export_variables (const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 181 {
 182     char *text;
 183     GString *export_vars_string;
 184     size_t i;
 185 
 186     /* *INDENT-OFF* */
 187     struct
 188     {
 189         const char symbol;
 190         const char *name;
 191         const gboolean is_result_quoted;
 192     } export_variables[] = {
 193         {'p', "MC_EXT_BASENAME", FALSE},
 194         {'d', "MC_EXT_CURRENTDIR", FALSE},
 195         {'s', "MC_EXT_SELECTED", TRUE},
 196         {'t', "MC_EXT_ONLYTAGGED", TRUE},
 197         {'\0', NULL, FALSE}
 198     };
 199     /* *INDENT-ON* */
 200 
 201     text = exec_get_file_name (filename_vpath);
 202     if (text == NULL)
 203         return NULL;
 204 
 205     export_vars_string = g_string_new ("MC_EXT_FILENAME=");
 206     g_string_append_printf (export_vars_string, "%s\nexport MC_EXT_FILENAME\n", text);
 207     g_free (text);
 208 
 209     for (i = 0; export_variables[i].name != NULL; i++)
 210     {
 211         text =
 212             exec_expand_format (export_variables[i].symbol, export_variables[i].is_result_quoted);
 213         if (text != NULL)
 214         {
 215             g_string_append_printf (export_vars_string,
 216                                     "%s=%s\nexport %s\n", export_variables[i].name, text,
 217                                     export_variables[i].name);
 218             g_free (text);
 219         }
 220     }
 221 
 222     return export_vars_string;
 223 }
 224 
 225 /* --------------------------------------------------------------------------------------------- */
 226 
 227 static GString *
 228 exec_make_shell_string (const char *lc_data, const vfs_path_t * filename_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
 229 {
 230     GString *shell_string;
 231     char lc_prompt[80] = "\0";
 232     gboolean parameter_found = FALSE;
 233     gboolean expand_prefix_found = FALSE;
 234 
 235     shell_string = g_string_new ("");
 236 
 237     for (; *lc_data != '\0' && *lc_data != '\n'; lc_data++)
 238     {
 239         if (parameter_found)
 240         {
 241             if (*lc_data == '}')
 242             {
 243                 char *parameter;
 244 
 245                 parameter_found = FALSE;
 246                 parameter =
 247                     input_dialog (_("Parameter"), lc_prompt, MC_HISTORY_EXT_PARAMETER, "",
 248                                   INPUT_COMPLETE_NONE);
 249                 if (parameter == NULL)
 250                 {
 251                     /* User canceled */
 252                     g_string_free (shell_string, TRUE);
 253                     exec_cleanup_file_name (filename_vpath, FALSE);
 254                     return NULL;
 255                 }
 256                 g_string_append (shell_string, parameter);
 257                 written_nonspace = TRUE;
 258                 g_free (parameter);
 259             }
 260             else
 261             {
 262                 size_t len = strlen (lc_prompt);
 263 
 264                 if (len < sizeof (lc_prompt) - 1)
 265                 {
 266                     lc_prompt[len] = *lc_data;
 267                     lc_prompt[len + 1] = '\0';
 268                 }
 269             }
 270         }
 271         else if (expand_prefix_found)
 272         {
 273             expand_prefix_found = FALSE;
 274             if (*lc_data == '{')
 275                 parameter_found = TRUE;
 276             else
 277             {
 278                 int i;
 279                 char *v;
 280 
 281                 i = check_format_view (lc_data);
 282                 if (i != 0)
 283                 {
 284                     lc_data += i - 1;
 285                     run_view = TRUE;
 286                 }
 287                 else
 288                 {
 289                     i = check_format_cd (lc_data);
 290                     if (i > 0)
 291                     {
 292                         is_cd = TRUE;
 293                         quote_func = fake_name_quote;
 294                         do_local_copy = FALSE;
 295                         pbuffer = buffer;
 296                         lc_data += i - 1;
 297                     }
 298                     else
 299                     {
 300                         i = check_format_var (lc_data, &v);
 301                         if (i > 0 && v != NULL)
 302                         {
 303                             g_string_append (shell_string, v);
 304                             g_free (v);
 305                             lc_data += i;
 306                         }
 307                         else
 308                         {
 309                             char *text;
 310 
 311                             if (*lc_data != 'f')
 312                                 text = expand_format (NULL, *lc_data, !is_cd);
 313                             else
 314                             {
 315                                 text = exec_get_file_name (filename_vpath);
 316                                 if (text == NULL)
 317                                 {
 318                                     g_string_free (shell_string, TRUE);
 319                                     return NULL;
 320                                 }
 321                             }
 322 
 323                             if (!is_cd)
 324                                 g_string_append (shell_string, text);
 325                             else
 326                             {
 327                                 strcpy (pbuffer, text);
 328                                 pbuffer = strchr (pbuffer, 0);
 329                             }
 330 
 331                             g_free (text);
 332                             written_nonspace = TRUE;
 333                         }
 334                     }
 335                 }
 336             }
 337         }
 338         else if (*lc_data == '%')
 339             expand_prefix_found = TRUE;
 340         else
 341         {
 342             if (!whitespace (*lc_data))
 343                 written_nonspace = TRUE;
 344             if (is_cd)
 345                 *(pbuffer++) = *lc_data;
 346             else
 347                 g_string_append_c (shell_string, *lc_data);
 348         }
 349     }                           /* for */
 350 
 351     return shell_string;
 352 }
 353 
 354 /* --------------------------------------------------------------------------------------------- */
 355 
 356 static void
 357 exec_extension_view (void *target, char *cmd, const vfs_path_t * filename_vpath, int start_line)
     /* [previous][next][first][last][top][bottom][index][help]  */
 358 {
 359     mcview_mode_flags_t def_flags = {
 360         /* *INDENT-OFF* */
 361         .wrap = FALSE,
 362         .hex = mcview_global_flags.hex,
 363         .magic = FALSE,
 364         .nroff = mcview_global_flags.nroff
 365         /* *INDENT-ON* */
 366     };
 367 
 368     mcview_mode_flags_t changed_flags;
 369 
 370     mcview_clear_mode_flags (&changed_flags);
 371     mcview_altered_flags.hex = FALSE;
 372     mcview_altered_flags.nroff = FALSE;
 373     if (def_flags.hex != mcview_global_flags.hex)
 374         changed_flags.hex = TRUE;
 375     if (def_flags.nroff != mcview_global_flags.nroff)
 376         changed_flags.nroff = TRUE;
 377 
 378     if (target == NULL)
 379         mcview_viewer (cmd, filename_vpath, start_line, 0, 0);
 380     else
 381         mcview_load ((WView *) target, cmd, vfs_path_as_str (filename_vpath), start_line, 0, 0);
 382 
 383     if (changed_flags.hex && !mcview_altered_flags.hex)
 384         mcview_global_flags.hex = def_flags.hex;
 385     if (changed_flags.nroff && !mcview_altered_flags.nroff)
 386         mcview_global_flags.nroff = def_flags.nroff;
 387 
 388     dialog_switch_process_pending ();
 389 }
 390 
 391 /* --------------------------------------------------------------------------------------------- */
 392 
 393 static void
 394 exec_extension_cd (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 395 {
 396     char *q;
 397     vfs_path_t *p_vpath;
 398 
 399     *pbuffer = '\0';
 400     pbuffer = buffer;
 401     /* Search last non-space character. Start search at the end in order
 402        not to short filenames containing spaces. */
 403     q = pbuffer + strlen (pbuffer) - 1;
 404     while (q >= pbuffer && whitespace (*q))
 405         q--;
 406     q[1] = 0;
 407 
 408     p_vpath = vfs_path_from_str_flags (pbuffer, VPF_NO_CANON);
 409     panel_cd (panel, p_vpath, cd_parse_command);
 410     vfs_path_free (p_vpath);
 411 }
 412 
 413 
 414 /* --------------------------------------------------------------------------------------------- */
 415 
 416 static vfs_path_t *
 417 exec_extension (WPanel * panel, void *target, const vfs_path_t * filename_vpath,
     /* [previous][next][first][last][top][bottom][index][help]  */
 418                 const char *lc_data, int start_line)
 419 {
 420     GString *shell_string, *export_variables;
 421     vfs_path_t *script_vpath = NULL;
 422     int cmd_file_fd;
 423     FILE *cmd_file;
 424     char *cmd = NULL;
 425 
 426     g_return_val_if_fail (lc_data != NULL, NULL);
 427 
 428     pbuffer = NULL;
 429     localmtime = 0;
 430     quote_func = name_quote;
 431     run_view = FALSE;
 432     is_cd = FALSE;
 433     written_nonspace = FALSE;
 434 
 435     /* Avoid making a local copy if we are doing a cd */
 436     do_local_copy = !vfs_file_is_local (filename_vpath);
 437 
 438     shell_string = exec_make_shell_string (lc_data, filename_vpath);
 439     if (shell_string == NULL)
 440         goto ret;
 441 
 442     if (is_cd)
 443     {
 444         exec_extension_cd (panel);
 445         g_string_free (shell_string, TRUE);
 446         goto ret;
 447     }
 448 
 449     /*
 450      * All commands should be run in /bin/sh regardless of user shell.
 451      * To do that, create temporary shell script and run it.
 452      * Sometimes it's not needed (e.g. for %cd and %view commands),
 453      * but it's easier to create it anyway.
 454      */
 455     cmd_file_fd = mc_mkstemps (&script_vpath, "mcext", SCRIPT_SUFFIX);
 456 
 457     if (cmd_file_fd == -1)
 458     {
 459         message (D_ERROR, MSG_ERROR,
 460                  _("Cannot create temporary command file\n%s"), unix_error_string (errno));
 461         goto ret;
 462     }
 463 
 464     cmd_file = fdopen (cmd_file_fd, "w");
 465     fputs ("#! /bin/sh\n\n", cmd_file);
 466 
 467     export_variables = exec_get_export_variables (filename_vpath);
 468     if (export_variables != NULL)
 469     {
 470         fputs (export_variables->str, cmd_file);
 471         g_string_free (export_variables, TRUE);
 472     }
 473 
 474     fputs (shell_string->str, cmd_file);
 475     g_string_free (shell_string, TRUE);
 476 
 477     /*
 478      * Make the script remove itself when it finishes.
 479      * Don't do it for the viewer - it may need to rerun the script,
 480      * so we clean up after calling view().
 481      */
 482     if (!run_view)
 483         fprintf (cmd_file, "\n/bin/rm -f %s\n", vfs_path_as_str (script_vpath));
 484 
 485     fclose (cmd_file);
 486 
 487     if ((run_view && !written_nonspace) || is_cd)
 488     {
 489         exec_cleanup_script (script_vpath);
 490         script_vpath = NULL;
 491     }
 492     else
 493     {
 494         /* Set executable flag on the command file ... */
 495         mc_chmod (script_vpath, S_IRWXU);
 496         /* ... but don't rely on it - run /bin/sh explicitly */
 497         cmd = g_strconcat ("/bin/sh ", vfs_path_as_str (script_vpath), (char *) NULL);
 498     }
 499 
 500     if (run_view)
 501     {
 502         /* If we've written whitespace only, then just load filename into view */
 503         if (!written_nonspace)
 504             exec_extension_view (target, NULL, filename_vpath, start_line);
 505         else
 506             exec_extension_view (target, cmd, filename_vpath, start_line);
 507     }
 508     else
 509     {
 510         shell_execute (cmd, EXECUTE_INTERNAL);
 511         if (mc_global.tty.console_flag != '\0')
 512         {
 513             handle_console (CONSOLE_SAVE);
 514             if (output_lines != 0 && mc_global.keybar_visible)
 515             {
 516                 unsigned char end_line;
 517 
 518                 end_line = LINES - (mc_global.keybar_visible ? 1 : 0) - 1;
 519                 show_console_contents (output_start_y, end_line - output_lines, end_line);
 520             }
 521         }
 522     }
 523 
 524     g_free (cmd);
 525 
 526     exec_cleanup_file_name (filename_vpath, TRUE);
 527   ret:
 528     return script_vpath;
 529 }
 530 
 531 /* --------------------------------------------------------------------------------------------- */
 532 /**
 533  * Run cmd_file with args, put result into buf.
 534  * If error, put '\0' into buf[0]
 535  * Return 1 if the data is valid, 0 otherwise, -1 for fatal errors.
 536  *
 537  * NOTES: buf is null-terminated string.
 538  */
 539 
 540 static int
 541 get_popen_information (const char *cmd_file, const char *args, char *buf, int buflen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 542 {
 543     gboolean read_bytes = FALSE;
 544     char *command;
 545     FILE *f;
 546 
 547     command = g_strconcat (cmd_file, args, " 2>/dev/null", (char *) NULL);
 548     f = popen (command, "r");
 549     g_free (command);
 550 
 551     if (f != NULL)
 552     {
 553 #ifdef __QNXNTO__
 554         if (setvbuf (f, NULL, _IOFBF, 0) != 0)
 555         {
 556             (void) pclose (f);
 557             return -1;
 558         }
 559 #endif
 560         read_bytes = (fgets (buf, buflen, f) != NULL);
 561         if (!read_bytes)
 562             buf[0] = '\0';      /* Paranoid termination */
 563         pclose (f);
 564     }
 565     else
 566     {
 567         buf[0] = '\0';          /* Paranoid termination */
 568         return -1;
 569     }
 570 
 571     buf[buflen - 1] = '\0';
 572 
 573     return read_bytes ? 1 : 0;
 574 }
 575 
 576 /* --------------------------------------------------------------------------------------------- */
 577 /**
 578  * Run the "file" command on the local file.
 579  * Return 1 if the data is valid, 0 otherwise, -1 for fatal errors.
 580  */
 581 
 582 static int
 583 get_file_type_local (const vfs_path_t * filename_vpath, char *buf, int buflen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 584 {
 585     char *tmp;
 586     int ret;
 587 
 588     tmp = name_quote (vfs_path_get_last_path_str (filename_vpath), FALSE);
 589     ret = get_popen_information (FILE_CMD, tmp, buf, buflen);
 590     g_free (tmp);
 591 
 592     return ret;
 593 }
 594 
 595 /* --------------------------------------------------------------------------------------------- */
 596 /**
 597  * Run the "enca" command on the local file.
 598  * Return 1 if the data is valid, 0 otherwise, -1 for fatal errors.
 599  */
 600 
 601 #ifdef HAVE_CHARSET
 602 static int
 603 get_file_encoding_local (const vfs_path_t * filename_vpath, char *buf, int buflen)
     /* [previous][next][first][last][top][bottom][index][help]  */
 604 {
 605     char *tmp, *lang, *args;
 606     int ret;
 607 
 608     tmp = name_quote (vfs_path_get_last_path_str (filename_vpath), FALSE);
 609     lang = name_quote (autodetect_codeset, FALSE);
 610     args = g_strconcat (" -L", lang, " -i ", tmp, (char *) NULL);
 611 
 612     ret = get_popen_information ("enca", args, buf, buflen);
 613 
 614     g_free (args);
 615     g_free (lang);
 616     g_free (tmp);
 617 
 618     return ret;
 619 }
 620 #endif /* HAVE_CHARSET */
 621 
 622 /* --------------------------------------------------------------------------------------------- */
 623 /**
 624  * Invoke the "file" command on the file and match its output against PTR.
 625  * have_type is a flag that is set if we already have tried to determine
 626  * the type of that file.
 627  * Return TRUE for match, FALSE otherwise.
 628  */
 629 
 630 static gboolean
 631 regex_check_type (const vfs_path_t * filename_vpath, const char *ptr, gboolean case_insense,
     /* [previous][next][first][last][top][bottom][index][help]  */
 632                   gboolean * have_type, GError ** mcerror)
 633 {
 634     gboolean found = FALSE;
 635 
 636     /* Following variables are valid if *have_type is TRUE */
 637     static char content_string[2048];
 638     static size_t content_shift = 0;
 639     static int got_data = 0;
 640 
 641     mc_return_val_if_error (mcerror, FALSE);
 642 
 643     if (!use_file_to_check_type)
 644         return FALSE;
 645 
 646     if (!*have_type)
 647     {
 648         vfs_path_t *localfile_vpath;
 649         const char *realname;   /* name used with "file" */
 650 
 651 #ifdef HAVE_CHARSET
 652         static char encoding_id[21];    /* CSISO51INISCYRILLIC -- 20 */
 653         int got_encoding_data;
 654 #endif /* HAVE_CHARSET */
 655 
 656         /* Don't repeate even unsuccessful checks */
 657         *have_type = TRUE;
 658 
 659         localfile_vpath = mc_getlocalcopy (filename_vpath);
 660         if (localfile_vpath == NULL)
 661         {
 662             mc_propagate_error (mcerror, 0, _("Cannot fetch a local copy of %s"),
 663                                 vfs_path_as_str (filename_vpath));
 664             return FALSE;
 665         }
 666 
 667         realname = vfs_path_get_last_path_str (localfile_vpath);
 668 
 669 #ifdef HAVE_CHARSET
 670         got_encoding_data = is_autodetect_codeset_enabled
 671             ? get_file_encoding_local (localfile_vpath, encoding_id, sizeof (encoding_id)) : 0;
 672 
 673         if (got_encoding_data > 0)
 674         {
 675             char *pp;
 676             int cp_id;
 677 
 678             pp = strchr (encoding_id, '\n');
 679             if (pp != NULL)
 680                 *pp = '\0';
 681 
 682             cp_id = get_codepage_index (encoding_id);
 683             if (cp_id == -1)
 684                 cp_id = default_source_codepage;
 685 
 686             do_set_codepage (cp_id);
 687         }
 688 #endif /* HAVE_CHARSET */
 689 
 690         got_data = get_file_type_local (localfile_vpath, content_string, sizeof (content_string));
 691 
 692         mc_ungetlocalcopy (filename_vpath, localfile_vpath, FALSE);
 693 
 694         if (got_data > 0)
 695         {
 696             char *pp;
 697             size_t real_len;
 698 
 699             pp = strchr (content_string, '\n');
 700             if (pp != NULL)
 701                 *pp = '\0';
 702 
 703             real_len = strlen (realname);
 704 
 705             if (strncmp (content_string, realname, real_len) == 0)
 706             {
 707                 /* Skip "realname: " */
 708                 content_shift = real_len;
 709                 if (content_string[content_shift] == ':')
 710                 {
 711                     /* Solaris' file prints tab(s) after ':' */
 712                     for (content_shift++; whitespace (content_string[content_shift]);
 713                          content_shift++)
 714                         ;
 715                 }
 716             }
 717         }
 718         else
 719         {
 720             /* No data */
 721             content_string[0] = '\0';
 722         }
 723         vfs_path_free (localfile_vpath);
 724     }
 725 
 726     if (got_data == -1)
 727     {
 728         mc_propagate_error (mcerror, 0, "%s", _("Pipe failed"));
 729         return FALSE;
 730     }
 731 
 732     if (content_string[0] != '\0')
 733     {
 734         mc_search_t *search;
 735 
 736         search = mc_search_new (ptr, DEFAULT_CHARSET);
 737         if (search != NULL)
 738         {
 739             search->search_type = MC_SEARCH_T_REGEX;
 740             search->is_case_sensitive = !case_insense;
 741             found = mc_search_run (search, content_string + content_shift, 0, -1, NULL);
 742             mc_search_free (search);
 743         }
 744         else
 745         {
 746             mc_propagate_error (mcerror, 0, "%s", _("Regular expression error"));
 747         }
 748     }
 749 
 750     return found;
 751 }
 752 
 753 /* --------------------------------------------------------------------------------------------- */
 754 /*** public functions ****************************************************************************/
 755 /* --------------------------------------------------------------------------------------------- */
 756 
 757 void
 758 flush_extension_file (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 759 {
 760     MC_PTR_FREE (data);
 761 }
 762 
 763 /* --------------------------------------------------------------------------------------------- */
 764 /**
 765  * The second argument is action, i.e. Open, View or Edit
 766  * Use target object to open file in.
 767  *
 768  * This function returns:
 769  *
 770  * -1 for a failure or user interrupt
 771  * 0 if no command was run
 772  * 1 if some command was run
 773  *
 774  * If action == "View" then a parameter is checked in the form of "View:%d",
 775  * if the value for %d exists, then the viewer is started up at that line number.
 776  */
 777 
 778 int
 779 regex_command_for (void *target, const vfs_path_t * filename_vpath, const char *action,
     /* [previous][next][first][last][top][bottom][index][help]  */
 780                    vfs_path_t ** script_vpath)
 781 {
 782     char *p, *q, *r, c;
 783     const char *filename;
 784     size_t file_len;
 785     gboolean found = FALSE;
 786     gboolean error_flag = FALSE;
 787     int ret = 0;
 788     struct stat mystat;
 789     int view_at_line_number = 0;
 790     char *include_target = NULL;
 791     size_t include_target_len = 0;
 792     gboolean have_type = FALSE; /* Flag used by regex_check_type() */
 793 
 794     if (filename_vpath == NULL)
 795         return 0;
 796 
 797     if (script_vpath != NULL)
 798         *script_vpath = NULL;
 799 
 800     /* Check for the special View:%d parameter */
 801     if (strncmp (action, "View:", 5) == 0)
 802     {
 803         view_at_line_number = atoi (action + 5);
 804         action = "View";
 805     }
 806 
 807     if (data == NULL)
 808     {
 809         char *extension_file;
 810         gboolean mc_user_ext = TRUE;
 811         gboolean home_error = FALSE;
 812 
 813         extension_file = mc_config_get_full_path (MC_FILEBIND_FILE);
 814         if (!exist_file (extension_file))
 815         {
 816             g_free (extension_file);
 817           check_stock_mc_ext:
 818             extension_file = mc_build_filename (mc_global.sysconfig_dir, MC_LIB_EXT, (char *) NULL);
 819             if (!exist_file (extension_file))
 820             {
 821                 g_free (extension_file);
 822                 extension_file =
 823                     mc_build_filename (mc_global.share_data_dir, MC_LIB_EXT, (char *) NULL);
 824             }
 825             mc_user_ext = FALSE;
 826         }
 827 
 828         g_file_get_contents (extension_file, &data, NULL, NULL);
 829         g_free (extension_file);
 830         if (data == NULL)
 831             return 0;
 832 
 833         if (strstr (data, "default/") == NULL)
 834         {
 835             if (strstr (data, "regex/") == NULL && strstr (data, "shell/") == NULL &&
 836                 strstr (data, "type/") == NULL)
 837             {
 838                 MC_PTR_FREE (data);
 839 
 840                 if (!mc_user_ext)
 841                 {
 842                     char *title;
 843 
 844                     title = g_strdup_printf (_(" %s%s file error"),
 845                                              mc_global.sysconfig_dir, MC_LIB_EXT);
 846                     message (D_ERROR, title, _("The format of the %smc.ext "
 847                                                "file has changed with version 3.0. It seems that "
 848                                                "the installation failed. Please fetch a fresh "
 849                                                "copy from the Midnight Commander package."),
 850                              mc_global.sysconfig_dir);
 851                     g_free (title);
 852                     return 0;
 853                 }
 854 
 855                 home_error = TRUE;
 856                 goto check_stock_mc_ext;
 857             }
 858         }
 859 
 860         if (home_error)
 861         {
 862             char *filebind_filename;
 863             char *title;
 864 
 865             filebind_filename = mc_config_get_full_path (MC_FILEBIND_FILE);
 866             title = g_strdup_printf (_("%s file error"), filebind_filename);
 867             message (D_ERROR, title,
 868                      _("The format of the %s file has "
 869                        "changed with version 3.0. You may either want to copy "
 870                        "it from %smc.ext or use that file as an example of how to write it."),
 871                      filebind_filename, mc_global.sysconfig_dir);
 872             g_free (filebind_filename);
 873             g_free (title);
 874         }
 875     }
 876 
 877     mc_stat (filename_vpath, &mystat);
 878 
 879     filename = vfs_path_get_last_path_str (filename_vpath);
 880     filename = x_basename (filename);
 881     file_len = strlen (filename);
 882 
 883     for (p = data; *p != '\0'; p++)
 884     {
 885         for (q = p; whitespace (*q); q++)
 886             ;
 887         if (*q == '\n' || *q == '\0')
 888             p = q;              /* empty line */
 889         if (*p == '#')          /* comment */
 890             while (*p != '\0' && *p != '\n')
 891                 p++;
 892         if (*p == '\n')
 893             continue;
 894         if (*p == '\0')
 895             break;
 896         if (p == q)
 897         {
 898             /* i.e. starts in the first column, should be keyword/descNL */
 899             gboolean case_insense;
 900 
 901             found = FALSE;
 902             q = strchr (p, '\n');
 903             if (q == NULL)
 904                 q = strchr (p, '\0');
 905             c = *q;
 906             *q = '\0';
 907             if (include_target != NULL)
 908             {
 909                 if ((strncmp (p, "include/", 8) == 0)
 910                     && (strncmp (p + 8, include_target, include_target_len) == 0))
 911                     found = TRUE;
 912             }
 913             else if (strncmp (p, "regex/", 6) == 0)
 914             {
 915                 mc_search_t *search;
 916 
 917                 p += 6;
 918                 case_insense = (strncmp (p, "i/", 2) == 0);
 919                 if (case_insense)
 920                     p += 2;
 921 
 922                 search = mc_search_new (p, DEFAULT_CHARSET);
 923                 if (search != NULL)
 924                 {
 925                     search->search_type = MC_SEARCH_T_REGEX;
 926                     search->is_case_sensitive = !case_insense;
 927                     found = mc_search_run (search, filename, 0, file_len, NULL);
 928                     mc_search_free (search);
 929                 }
 930             }
 931             else if (strncmp (p, "directory/", 10) == 0)
 932             {
 933                 if (S_ISDIR (mystat.st_mode)
 934                     && mc_search (p + 10, DEFAULT_CHARSET, vfs_path_as_str (filename_vpath),
 935                                   MC_SEARCH_T_REGEX))
 936                     found = TRUE;
 937             }
 938             else if (strncmp (p, "shell/", 6) == 0)
 939             {
 940                 int (*cmp_func) (const char *s1, const char *s2, size_t n) = strncmp;
 941 
 942                 p += 6;
 943                 case_insense = (strncmp (p, "i/", 2) == 0);
 944                 if (case_insense)
 945                 {
 946                     p += 2;
 947                     cmp_func = strncasecmp;
 948                 }
 949 
 950                 if (*p == '.' && file_len >= (size_t) (q - p))
 951                 {
 952                     if (cmp_func (p, filename + file_len - (q - p), q - p) == 0)
 953                         found = TRUE;
 954                 }
 955                 else
 956                 {
 957                     if ((size_t) (q - p) == file_len && cmp_func (p, filename, file_len) == 0)
 958                         found = TRUE;
 959                 }
 960             }
 961             else if (strncmp (p, "type/", 5) == 0)
 962             {
 963                 GError *mcerror = NULL;
 964 
 965                 p += 5;
 966 
 967                 case_insense = (strncmp (p, "i/", 2) == 0);
 968                 if (case_insense)
 969                     p += 2;
 970 
 971                 found = regex_check_type (filename_vpath, p, case_insense, &have_type, &mcerror);
 972                 if (mc_error_message (&mcerror, NULL))
 973                     error_flag = TRUE;  /* leave it if file cannot be opened */
 974             }
 975             else if (strncmp (p, "default/", 8) == 0)
 976                 found = TRUE;
 977 
 978             *q = c;
 979         }
 980         else
 981         {                       /* List of actions */
 982             p = q;
 983             q = strchr (p, '\n');
 984             if (q == NULL)
 985                 q = strchr (p, '\0');
 986             if (found && !error_flag)
 987             {
 988                 r = strchr (p, '=');
 989                 if (r != NULL)
 990                 {
 991                     c = *r;
 992                     *r = '\0';
 993                     if (strcmp (p, "Include") == 0)
 994                     {
 995                         char *t;
 996 
 997                         include_target = p + 8;
 998                         t = strchr (include_target, '\n');
 999 
1000                         if (t != NULL)
1001                             include_target_len = (size_t) (t - include_target);
1002                         else
1003                             include_target_len = strlen (include_target);
1004 
1005                         *r = c;
1006                         p = q;
1007                         found = FALSE;
1008 
1009                         if (*p == '\0')
1010                             break;
1011                         continue;
1012                     }
1013 
1014                     if (strcmp (action, p) != 0)
1015                         *r = c;
1016                     else
1017                     {
1018                         *r = c;
1019 
1020                         for (p = r + 1; whitespace (*p); p++)
1021                             ;
1022 
1023                         /* Empty commands just stop searching
1024                          * through, they don't do anything
1025                          */
1026                         if (p < q)
1027                         {
1028                             vfs_path_t *sv;
1029 
1030                             sv = exec_extension (current_panel, target, filename_vpath, r + 1,
1031                                                  view_at_line_number);
1032                             if (script_vpath != NULL)
1033                                 *script_vpath = sv;
1034                             else
1035                                 exec_cleanup_script (sv);
1036 
1037                             ret = 1;
1038                         }
1039                         break;
1040                     }
1041                 }
1042             }
1043         }
1044 
1045         p = q;
1046         if (*p == '\0')
1047             break;
1048     }
1049 
1050     return (error_flag ? -1 : ret);
1051 }
1052 
1053 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */