root/src/filemanager/panelize.c

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

DEFINITIONS

This source file includes following definitions.
  1. update_command
  2. panelize_callback
  3. init_panelize
  4. panelize_done
  5. add2panelize
  6. add2panelize_cmd
  7. remove_from_panelize
  8. do_external_panelize
  9. do_panelize_cd
  10. panelize_change_root
  11. panelize_save_panel
  12. panelize_absolutize_if_needed
  13. cd_panelize_cmd
  14. external_panelize
  15. load_panelize
  16. save_panelize
  17. done_panelize

   1 /*
   2    External panelize
   3 
   4    Copyright (C) 1995-2022
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Janne Kukonlehto, 1995
   9    Jakub Jelinek, 1995
  10    Andrew Borodin <aborodin@vmail.ru> 2011-2022
  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 panelize.c
  29  *  \brief Source: External panelization module
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <errno.h>
  35 #include <stdio.h>
  36 #include <string.h>
  37 #include <sys/types.h>
  38 #include <sys/stat.h>
  39 #include <unistd.h>
  40 
  41 #include "lib/global.h"
  42 
  43 #include "lib/skin.h"
  44 #include "lib/vfs/vfs.h"
  45 #include "lib/mcconfig.h"       /* Load/save directories panelize */
  46 #include "lib/strutil.h"
  47 #include "lib/util.h"
  48 #include "lib/widget.h"
  49 
  50 #include "src/setup.h"          /* For profile_bname */
  51 #include "src/history.h"
  52 
  53 #include "dir.h"
  54 #include "filemanager.h"        /* current_panel */
  55 #include "layout.h"             /* rotate_dash() */
  56 #include "panel.h"              /* WPanel */
  57 
  58 #include "panelize.h"
  59 
  60 /*** global variables ****************************************************************************/
  61 
  62 /*** file scope macro definitions ****************************************************************/
  63 
  64 #define UX 3
  65 #define UY 2
  66 
  67 #define B_ADD    B_USER
  68 #define B_REMOVE (B_USER + 1)
  69 
  70 /*** file scope type declarations ****************************************************************/
  71 
  72 /*** file scope variables ************************************************************************/
  73 
  74 static WListbox *l_panelize;
  75 static WDialog *panelize_dlg;
  76 static int last_listitem;
  77 static WInput *pname;
  78 
  79 static const char *panelize_section = "Panelize";
  80 
  81 /* Directory panelize */
  82 static struct panelize
  83 {
  84     char *command;
  85     char *label;
  86     struct panelize *next;
  87 } *panelize = NULL;
  88 
  89 /* --------------------------------------------------------------------------------------------- */
  90 /*** file scope functions ************************************************************************/
  91 /* --------------------------------------------------------------------------------------------- */
  92 
  93 static void
  94 update_command (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  95 {
  96     if (l_panelize->pos != last_listitem)
  97     {
  98         struct panelize *data = NULL;
  99 
 100         last_listitem = l_panelize->pos;
 101         listbox_get_current (l_panelize, NULL, (void **) &data);
 102         input_assign_text (pname, data->command);
 103         pname->point = 0;
 104         input_update (pname, TRUE);
 105     }
 106 }
 107 
 108 /* --------------------------------------------------------------------------------------------- */
 109 
 110 static cb_ret_t
 111 panelize_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 112 {
 113     switch (msg)
 114     {
 115     case MSG_INIT:
 116         group_default_callback (w, NULL, MSG_INIT, 0, NULL);
 117         MC_FALLTHROUGH;
 118 
 119     case MSG_NOTIFY:           /* MSG_NOTIFY is fired by the listbox to tell us the item has changed. */
 120         update_command ();
 121         return MSG_HANDLED;
 122 
 123     default:
 124         return dlg_default_callback (w, sender, msg, parm, data);
 125     }
 126 }
 127 
 128 /* --------------------------------------------------------------------------------------------- */
 129 
 130 static void
 131 init_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 132 {
 133     struct
 134     {
 135         int ret_cmd;
 136         button_flags_t flags;
 137         const char *text;
 138     } panelize_but[] =
 139     {
 140         /* *INDENT-OFF* */
 141         { B_ENTER, DEFPUSH_BUTTON, N_("Pane&lize") },
 142         { B_REMOVE, NORMAL_BUTTON, N_("&Remove") },
 143         { B_ADD, NORMAL_BUTTON, N_("&Add new") },
 144         { B_CANCEL, NORMAL_BUTTON, N_("&Cancel") }
 145         /* *INDENT-ON* */
 146     };
 147 
 148     WGroup *g;
 149 
 150     size_t i;
 151     int blen;
 152     int panelize_cols;
 153     struct panelize *current;
 154     int x, y;
 155 
 156     last_listitem = 0;
 157 
 158     do_refresh ();
 159 
 160     i = G_N_ELEMENTS (panelize_but);
 161     blen = i - 1;               /* gaps between buttons */
 162     while (i-- != 0)
 163     {
 164 #ifdef ENABLE_NLS
 165         panelize_but[i].text = _(panelize_but[i].text);
 166 #endif
 167         blen += str_term_width1 (panelize_but[i].text) + 3 + 1;
 168         if (panelize_but[i].flags == DEFPUSH_BUTTON)
 169             blen += 2;
 170     }
 171 
 172     panelize_cols = COLS - 6;
 173     panelize_cols = MAX (panelize_cols, blen + 4);
 174 
 175     panelize_dlg =
 176         dlg_create (TRUE, 0, 0, 20, panelize_cols, WPOS_CENTER, FALSE, dialog_colors,
 177                     panelize_callback, NULL, "[External panelize]", _("External panelize"));
 178     g = GROUP (panelize_dlg);
 179 
 180     /* add listbox to the dialogs */
 181     y = UY;
 182     group_add_widget (g, groupbox_new (y++, UX, 12, panelize_cols - UX * 2, ""));
 183 
 184     l_panelize = listbox_new (y, UX + 1, 10, panelize_cols - UX * 2 - 2, FALSE, NULL);
 185     for (current = panelize; current != NULL; current = current->next)
 186         listbox_add_item (l_panelize, LISTBOX_APPEND_AT_END, 0, current->label, current, FALSE);
 187     listbox_select_entry (l_panelize, listbox_search_text (l_panelize, _("Other command")));
 188     group_add_widget (g, l_panelize);
 189 
 190     y += WIDGET (l_panelize)->rect.lines + 1;
 191     group_add_widget (g, label_new (y++, UX, _("Command")));
 192     pname =
 193         input_new (y++, UX, input_colors, panelize_cols - UX * 2, "", "in",
 194                    INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES | INPUT_COMPLETE_COMMANDS |
 195                    INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES | INPUT_COMPLETE_CD |
 196                    INPUT_COMPLETE_SHELL_ESC);
 197     group_add_widget (g, pname);
 198 
 199     group_add_widget (g, hline_new (y++, -1, -1));
 200 
 201     x = (panelize_cols - blen) / 2;
 202     for (i = 0; i < G_N_ELEMENTS (panelize_but); i++)
 203     {
 204         WButton *b;
 205 
 206         b = button_new (y, x,
 207                         panelize_but[i].ret_cmd, panelize_but[i].flags, panelize_but[i].text, NULL);
 208         group_add_widget (g, b);
 209 
 210         x += button_get_len (b) + 1;
 211     }
 212 
 213     widget_select (WIDGET (l_panelize));
 214 }
 215 
 216 /* --------------------------------------------------------------------------------------------- */
 217 
 218 static void
 219 panelize_done (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 220 {
 221     widget_destroy (WIDGET (panelize_dlg));
 222     repaint_screen ();
 223 }
 224 
 225 /* --------------------------------------------------------------------------------------------- */
 226 
 227 static void
 228 add2panelize (char *label, char *command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 229 {
 230     struct panelize *current;
 231     struct panelize *old = NULL;
 232 
 233     current = panelize;
 234     while (current != NULL && strcmp (current->label, label) <= 0)
 235     {
 236         old = current;
 237         current = current->next;
 238     }
 239 
 240     if (old == NULL)
 241     {
 242         panelize = g_new (struct panelize, 1);
 243         panelize->label = label;
 244         panelize->command = command;
 245         panelize->next = current;
 246     }
 247     else
 248     {
 249         struct panelize *new;
 250 
 251         new = g_new (struct panelize, 1);
 252         new->label = label;
 253         new->command = command;
 254         old->next = new;
 255         new->next = current;
 256     }
 257 }
 258 
 259 /* --------------------------------------------------------------------------------------------- */
 260 
 261 static void
 262 add2panelize_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 263 {
 264     if (!input_is_empty (pname))
 265     {
 266         char *label;
 267 
 268         label = input_dialog (_("Add to external panelize"),
 269                               _("Enter command label:"), MC_HISTORY_FM_PANELIZE_ADD, "",
 270                               INPUT_COMPLETE_NONE);
 271         if (label == NULL || *label == '\0')
 272             g_free (label);
 273         else
 274             add2panelize (label, input_get_text (pname));
 275     }
 276 }
 277 
 278 /* --------------------------------------------------------------------------------------------- */
 279 
 280 static void
 281 remove_from_panelize (struct panelize *entry)
     /* [previous][next][first][last][top][bottom][index][help]  */
 282 {
 283     if (strcmp (entry->label, _("Other command")) != 0)
 284     {
 285         if (entry == panelize)
 286             panelize = panelize->next;
 287         else
 288         {
 289             struct panelize *current = panelize;
 290 
 291             while (current != NULL && current->next != entry)
 292                 current = current->next;
 293 
 294             if (current != NULL)
 295                 current->next = entry->next;
 296         }
 297 
 298         g_free (entry->label);
 299         g_free (entry->command);
 300         g_free (entry);
 301     }
 302 }
 303 
 304 /* --------------------------------------------------------------------------------------------- */
 305 
 306 static void
 307 do_external_panelize (char *command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 308 {
 309     dir_list *list = &current_panel->dir;
 310     mc_pipe_t *external;
 311     GError *error = NULL;
 312     GString *remain_file_name = NULL;
 313 
 314     external = mc_popen (command, TRUE, TRUE, &error);
 315     if (external == NULL)
 316     {
 317         message (D_ERROR, _("External panelize"), "%s", error->message);
 318         g_error_free (error);
 319         return;
 320     }
 321 
 322     /* Clear the counters and the directory list */
 323     panel_clean_dir (current_panel);
 324 
 325     panelize_change_root (current_panel->cwd_vpath);
 326 
 327     dir_list_init (list);
 328 
 329     while (TRUE)
 330     {
 331         GString *line;
 332         gboolean ok;
 333 
 334         /* init buffers before call of mc_pread() */
 335         external->out.len = MC_PIPE_BUFSIZE;
 336         external->err.len = MC_PIPE_BUFSIZE;
 337         external->err.null_term = TRUE;
 338 
 339         mc_pread (external, &error);
 340 
 341         if (error != NULL)
 342         {
 343             message (D_ERROR, MSG_ERROR, _("External panelize:\n%s"), error->message);
 344             g_error_free (error);
 345             break;
 346         }
 347 
 348         if (external->err.len > 0)
 349             message (D_ERROR, MSG_ERROR, _("External panelize:\n%s"), external->err.buf);
 350 
 351         if (external->out.len == MC_PIPE_STREAM_EOF)
 352             break;
 353 
 354         if (external->out.len == 0)
 355             continue;
 356 
 357         if (external->out.len == MC_PIPE_ERROR_READ)
 358         {
 359             message (D_ERROR, MSG_ERROR,
 360                      _("External panelize:\nfailed to read data from child stdout:\n%s"),
 361                      unix_error_string (external->out.error));
 362             break;
 363         }
 364 
 365         ok = TRUE;
 366 
 367         while (ok && (line = mc_pstream_get_string (&external->out)) != NULL)
 368         {
 369             char *name;
 370             gboolean link_to_dir, stale_link;
 371             struct stat st;
 372 
 373             /* handle a \n-separated file list */
 374 
 375             if (line->str[line->len - 1] == '\n')
 376             {
 377                 /* entire file name or last chunk */
 378 
 379                 g_string_truncate (line, line->len - 1);
 380 
 381                 /* join filename chunks */
 382                 if (remain_file_name != NULL)
 383                 {
 384                     g_string_append_len (remain_file_name, line->str, line->len);
 385                     g_string_free (line, TRUE);
 386                     line = remain_file_name;
 387                     remain_file_name = NULL;
 388                 }
 389             }
 390             else
 391             {
 392                 /* first or middle chunk of file name */
 393 
 394                 if (remain_file_name == NULL)
 395                     remain_file_name = line;
 396                 else
 397                 {
 398                     g_string_append_len (remain_file_name, line->str, line->len);
 399                     g_string_free (line, TRUE);
 400                 }
 401 
 402                 continue;
 403             }
 404 
 405             name = line->str;
 406 
 407             if (name[0] == '.' && IS_PATH_SEP (name[1]))
 408                 name += 2;
 409 
 410             if (handle_path (name, &st, &link_to_dir, &stale_link))
 411             {
 412                 ok = dir_list_append (list, name, &st, link_to_dir, stale_link);
 413 
 414                 if (ok)
 415                 {
 416                     file_mark (current_panel, list->len - 1, 0);
 417 
 418                     if ((list->len & 31) == 0)
 419                         rotate_dash (TRUE);
 420                 }
 421             }
 422 
 423             g_string_free (line, TRUE);
 424         }
 425     }
 426 
 427     if (remain_file_name != NULL)
 428         g_string_free (remain_file_name, TRUE);
 429 
 430     mc_pclose (external, NULL);
 431 
 432     current_panel->is_panelized = TRUE;
 433     panelize_absolutize_if_needed (current_panel);
 434 
 435     try_to_select (current_panel, NULL);
 436     panel_re_sort (current_panel);
 437     rotate_dash (FALSE);
 438 }
 439 
 440 /* --------------------------------------------------------------------------------------------- */
 441 
 442 static void
 443 do_panelize_cd (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 444 {
 445     int i;
 446     dir_list *list;
 447     gboolean panelized_same;
 448 
 449     dir_list_clean (&panel->dir);
 450     if (panelized_panel.root_vpath == NULL)
 451         panelize_change_root (current_panel->cwd_vpath);
 452 
 453     if (panelized_panel.list.len < 1)
 454         dir_list_init (&panelized_panel.list);
 455     else if (panelized_panel.list.len > panel->dir.size)
 456         dir_list_grow (&panel->dir, panelized_panel.list.len - panel->dir.size);
 457 
 458     list = &panel->dir;
 459     list->len = panelized_panel.list.len;
 460 
 461     panelized_same = vfs_path_equal (panelized_panel.root_vpath, panel->cwd_vpath);
 462 
 463     for (i = 0; i < panelized_panel.list.len; i++)
 464     {
 465         if (panelized_same || DIR_IS_DOTDOT (panelized_panel.list.list[i].fname->str))
 466             list->list[i].fname = mc_g_string_dup (panelized_panel.list.list[i].fname);
 467         else
 468         {
 469             vfs_path_t *tmp_vpath;
 470 
 471             tmp_vpath =
 472                 vfs_path_append_new (panelized_panel.root_vpath,
 473                                      panelized_panel.list.list[i].fname->str, (char *) NULL);
 474             list->list[i].fname = g_string_new (vfs_path_as_str (tmp_vpath));
 475             vfs_path_free (tmp_vpath, TRUE);
 476         }
 477         list->list[i].f.link_to_dir = panelized_panel.list.list[i].f.link_to_dir;
 478         list->list[i].f.stale_link = panelized_panel.list.list[i].f.stale_link;
 479         list->list[i].f.dir_size_computed = panelized_panel.list.list[i].f.dir_size_computed;
 480         list->list[i].f.marked = panelized_panel.list.list[i].f.marked;
 481         list->list[i].st = panelized_panel.list.list[i].st;
 482         list->list[i].sort_key = panelized_panel.list.list[i].sort_key;
 483         list->list[i].second_sort_key = panelized_panel.list.list[i].second_sort_key;
 484     }
 485 
 486     panel->is_panelized = TRUE;
 487     panelize_absolutize_if_needed (panel);
 488 
 489     try_to_select (panel, NULL);
 490 }
 491 
 492 /* --------------------------------------------------------------------------------------------- */
 493 /*** public functions ****************************************************************************/
 494 /* --------------------------------------------------------------------------------------------- */
 495 
 496 /**
 497  * Change root directory of panelized content.
 498  * @param new_root - object with new path.
 499  */
 500 void
 501 panelize_change_root (const vfs_path_t * new_root)
     /* [previous][next][first][last][top][bottom][index][help]  */
 502 {
 503     vfs_path_free (panelized_panel.root_vpath, TRUE);
 504     panelized_panel.root_vpath = vfs_path_clone (new_root);
 505 }
 506 
 507 /* --------------------------------------------------------------------------------------------- */
 508 
 509 void
 510 panelize_save_panel (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 511 {
 512     int i;
 513     dir_list *list = &panel->dir;
 514 
 515     panelize_change_root (current_panel->cwd_vpath);
 516 
 517     if (panelized_panel.list.len > 0)
 518         dir_list_clean (&panelized_panel.list);
 519     if (panel->dir.len == 0)
 520         return;
 521 
 522     if (panel->dir.len > panelized_panel.list.size)
 523         dir_list_grow (&panelized_panel.list, panel->dir.len - panelized_panel.list.size);
 524     panelized_panel.list.len = panel->dir.len;
 525 
 526     for (i = 0; i < panel->dir.len; i++)
 527     {
 528         panelized_panel.list.list[i].fname = mc_g_string_dup (list->list[i].fname);
 529         panelized_panel.list.list[i].f.link_to_dir = list->list[i].f.link_to_dir;
 530         panelized_panel.list.list[i].f.stale_link = list->list[i].f.stale_link;
 531         panelized_panel.list.list[i].f.dir_size_computed = list->list[i].f.dir_size_computed;
 532         panelized_panel.list.list[i].f.marked = list->list[i].f.marked;
 533         panelized_panel.list.list[i].st = list->list[i].st;
 534         panelized_panel.list.list[i].sort_key = list->list[i].sort_key;
 535         panelized_panel.list.list[i].second_sort_key = list->list[i].second_sort_key;
 536     }
 537 }
 538 
 539 /* --------------------------------------------------------------------------------------------- */
 540 
 541 /**
 542  * Conditionally switches a panel's directory to "/" (root).
 543  *
 544  * If a panelized panel's listing contain absolute paths, this function
 545  * sets the panel's directory to "/". Otherwise it does nothing.
 546  *
 547  * Rationale:
 548  *
 549  * This makes tokenized strings like "%d/%p" work. This also makes other
 550  * places work where such naive concatenation is done in code (e.g., when
 551  * pressing ctrl+shift+enter, for CK_PutCurrentFullSelected).
 552  *
 553  * When to call:
 554  *
 555  * You should always call this function after you populate the listing
 556  * of a panelized panel.
 557  */
 558 void
 559 panelize_absolutize_if_needed (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 560 {
 561     const dir_list *const list = &panel->dir;
 562 
 563     /* Note: We don't support mixing of absolute and relative paths, which is
 564      * why it's ok for us to check only the 1st entry. */
 565     if (list->len > 1 && g_path_is_absolute (list->list[1].fname->str))
 566     {
 567         vfs_path_t *root;
 568 
 569         root = vfs_path_from_str (PATH_SEP_STR);
 570         panel_set_cwd (panel, root);
 571         if (panel == current_panel)
 572             mc_chdir (root);
 573         vfs_path_free (root, TRUE);
 574     }
 575 }
 576 
 577 /* --------------------------------------------------------------------------------------------- */
 578 
 579 void
 580 cd_panelize_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 581 {
 582     if (!SELECTED_IS_PANEL)
 583         create_panel (MENU_PANEL_IDX, view_listing);
 584 
 585     do_panelize_cd (PANEL (get_panel_widget (MENU_PANEL_IDX)));
 586 }
 587 
 588 /* --------------------------------------------------------------------------------------------- */
 589 
 590 void
 591 external_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 592 {
 593     if (!vfs_current_is_local ())
 594     {
 595         message (D_ERROR, MSG_ERROR, _("Cannot run external panelize in a non-local directory"));
 596         return;
 597     }
 598 
 599     init_panelize ();
 600 
 601     /* display file info */
 602     tty_setcolor (SELECTED_COLOR);
 603 
 604     switch (dlg_run (panelize_dlg))
 605     {
 606     case B_CANCEL:
 607         break;
 608 
 609     case B_ADD:
 610         add2panelize_cmd ();
 611         break;
 612 
 613     case B_REMOVE:
 614         {
 615             struct panelize *entry;
 616 
 617             listbox_get_current (l_panelize, NULL, (void **) &entry);
 618             remove_from_panelize (entry);
 619             break;
 620         }
 621 
 622     case B_ENTER:
 623         if (!input_is_empty (pname))
 624         {
 625             char *cmd;
 626 
 627             cmd = input_get_text (pname);
 628             widget_destroy (WIDGET (panelize_dlg));
 629             do_external_panelize (cmd);
 630             g_free (cmd);
 631             repaint_screen ();
 632             return;
 633         }
 634         break;
 635 
 636     default:
 637         break;
 638     }
 639 
 640     panelize_done ();
 641 }
 642 
 643 /* --------------------------------------------------------------------------------------------- */
 644 
 645 void
 646 load_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 647 {
 648     char **keys;
 649 
 650     keys = mc_config_get_keys (mc_global.main_config, panelize_section, NULL);
 651 
 652     add2panelize (g_strdup (_("Other command")), g_strdup (""));
 653 
 654     if (*keys == NULL)
 655     {
 656         add2panelize (g_strdup (_("Modified git files")), g_strdup ("git ls-files --modified"));
 657         add2panelize (g_strdup (_("Find rejects after patching")),
 658                       g_strdup ("find . -name \\*.rej -print"));
 659         add2panelize (g_strdup (_("Find *.orig after patching")),
 660                       g_strdup ("find . -name \\*.orig -print"));
 661         add2panelize (g_strdup (_("Find SUID and SGID programs")),
 662                       g_strdup
 663                       ("find . \\( \\( -perm -04000 -a -perm /011 \\) -o \\( -perm -02000 -a -perm /01 \\) \\) -print"));
 664     }
 665     else
 666     {
 667         GIConv conv;
 668         char **profile_keys;
 669 
 670         conv = str_crt_conv_from ("UTF-8");
 671 
 672         for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
 673         {
 674             GString *buffer;
 675 
 676             if (mc_global.utf8_display || conv == INVALID_CONV)
 677                 buffer = g_string_new (*profile_keys);
 678             else
 679             {
 680                 buffer = g_string_new ("");
 681                 if (str_convert (conv, *profile_keys, buffer) == ESTR_FAILURE)
 682                     g_string_assign (buffer, *profile_keys);
 683             }
 684 
 685             add2panelize (g_string_free (buffer, FALSE),
 686                           mc_config_get_string (mc_global.main_config, panelize_section,
 687                                                 *profile_keys, ""));
 688         }
 689 
 690         str_close_conv (conv);
 691     }
 692 
 693     g_strfreev (keys);
 694 }
 695 
 696 /* --------------------------------------------------------------------------------------------- */
 697 
 698 void
 699 save_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 700 {
 701     struct panelize *current;
 702 
 703     mc_config_del_group (mc_global.main_config, panelize_section);
 704 
 705     for (current = panelize; current != NULL; current = current->next)
 706         if (strcmp (current->label, _("Other command")) != 0)
 707             mc_config_set_string (mc_global.main_config,
 708                                   panelize_section, current->label, current->command);
 709 }
 710 
 711 /* --------------------------------------------------------------------------------------------- */
 712 
 713 void
 714 done_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 715 {
 716     struct panelize *current, *next;
 717 
 718     for (current = panelize; current != NULL; current = next)
 719     {
 720         next = current->next;
 721         g_free (current->label);
 722         g_free (current->command);
 723         g_free (current);
 724     }
 725 }
 726 
 727 /* --------------------------------------------------------------------------------------------- */

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