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 
 338         mc_pread (external, &error);
 339 
 340         if (error != NULL)
 341         {
 342             message (D_ERROR, MSG_ERROR, _("External panelize:\n%s"), error->message);
 343             g_error_free (error);
 344             break;
 345         }
 346 
 347         if (external->err.len > 0)
 348             message (D_ERROR, MSG_ERROR, _("External panelize:\n%s"), external->err.buf);
 349 
 350         if (external->out.len == MC_PIPE_STREAM_EOF)
 351             break;
 352 
 353         if (external->out.len == 0)
 354             continue;
 355 
 356         if (external->out.len == MC_PIPE_ERROR_READ)
 357         {
 358             message (D_ERROR, MSG_ERROR,
 359                      _("External panelize:\nfailed to read data from child stdout:\n%s"),
 360                      unix_error_string (external->out.error));
 361             break;
 362         }
 363 
 364         ok = TRUE;
 365 
 366         while (ok && (line = mc_pstream_get_string (&external->out)) != NULL)
 367         {
 368             char *name;
 369             gboolean link_to_dir, stale_link;
 370             struct stat st;
 371 
 372             /* handle a \n-separated file list */
 373 
 374             if (line->str[line->len - 1] == '\n')
 375             {
 376                 /* entire file name or last chunk */
 377 
 378                 g_string_truncate (line, line->len - 1);
 379 
 380                 /* join filename chunks */
 381                 if (remain_file_name != NULL)
 382                 {
 383                     g_string_append_len (remain_file_name, line->str, line->len);
 384                     g_string_free (line, TRUE);
 385                     line = remain_file_name;
 386                     remain_file_name = NULL;
 387                 }
 388             }
 389             else
 390             {
 391                 /* first or middle chunk of file name */
 392 
 393                 if (remain_file_name == NULL)
 394                     remain_file_name = line;
 395                 else
 396                 {
 397                     g_string_append_len (remain_file_name, line->str, line->len);
 398                     g_string_free (line, TRUE);
 399                 }
 400 
 401                 continue;
 402             }
 403 
 404             name = line->str;
 405 
 406             if (name[0] == '.' && IS_PATH_SEP (name[1]))
 407                 name += 2;
 408 
 409             if (handle_path (name, &st, &link_to_dir, &stale_link))
 410             {
 411                 ok = dir_list_append (list, name, &st, link_to_dir, stale_link);
 412 
 413                 if (ok)
 414                 {
 415                     file_mark (current_panel, list->len - 1, 0);
 416 
 417                     if ((list->len & 31) == 0)
 418                         rotate_dash (TRUE);
 419                 }
 420             }
 421 
 422             g_string_free (line, TRUE);
 423         }
 424     }
 425 
 426     if (remain_file_name != NULL)
 427         g_string_free (remain_file_name, TRUE);
 428 
 429     mc_pclose (external, NULL);
 430 
 431     current_panel->is_panelized = TRUE;
 432     panelize_absolutize_if_needed (current_panel);
 433 
 434     try_to_select (current_panel, NULL);
 435     panel_re_sort (current_panel);
 436     rotate_dash (FALSE);
 437 }
 438 
 439 /* --------------------------------------------------------------------------------------------- */
 440 
 441 static void
 442 do_panelize_cd (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 443 {
 444     int i;
 445     dir_list *list;
 446     gboolean panelized_same;
 447 
 448     dir_list_clean (&panel->dir);
 449     if (panelized_panel.root_vpath == NULL)
 450         panelize_change_root (current_panel->cwd_vpath);
 451 
 452     if (panelized_panel.list.len < 1)
 453         dir_list_init (&panelized_panel.list);
 454     else if (panelized_panel.list.len > panel->dir.size)
 455         dir_list_grow (&panel->dir, panelized_panel.list.len - panel->dir.size);
 456 
 457     list = &panel->dir;
 458     list->len = panelized_panel.list.len;
 459 
 460     panelized_same = vfs_path_equal (panelized_panel.root_vpath, panel->cwd_vpath);
 461 
 462     for (i = 0; i < panelized_panel.list.len; i++)
 463     {
 464         if (panelized_same || DIR_IS_DOTDOT (panelized_panel.list.list[i].fname->str))
 465             list->list[i].fname = mc_g_string_dup (panelized_panel.list.list[i].fname);
 466         else
 467         {
 468             vfs_path_t *tmp_vpath;
 469 
 470             tmp_vpath =
 471                 vfs_path_append_new (panelized_panel.root_vpath,
 472                                      panelized_panel.list.list[i].fname->str, (char *) NULL);
 473             list->list[i].fname = g_string_new (vfs_path_as_str (tmp_vpath));
 474             vfs_path_free (tmp_vpath, TRUE);
 475         }
 476         list->list[i].f.link_to_dir = panelized_panel.list.list[i].f.link_to_dir;
 477         list->list[i].f.stale_link = panelized_panel.list.list[i].f.stale_link;
 478         list->list[i].f.dir_size_computed = panelized_panel.list.list[i].f.dir_size_computed;
 479         list->list[i].f.marked = panelized_panel.list.list[i].f.marked;
 480         list->list[i].st = panelized_panel.list.list[i].st;
 481         list->list[i].sort_key = panelized_panel.list.list[i].sort_key;
 482         list->list[i].second_sort_key = panelized_panel.list.list[i].second_sort_key;
 483     }
 484 
 485     panel->is_panelized = TRUE;
 486     panelize_absolutize_if_needed (panel);
 487 
 488     try_to_select (panel, NULL);
 489 }
 490 
 491 /* --------------------------------------------------------------------------------------------- */
 492 /*** public functions ****************************************************************************/
 493 /* --------------------------------------------------------------------------------------------- */
 494 
 495 /**
 496  * Change root directory of panelized content.
 497  * @param new_root - object with new path.
 498  */
 499 void
 500 panelize_change_root (const vfs_path_t * new_root)
     /* [previous][next][first][last][top][bottom][index][help]  */
 501 {
 502     vfs_path_free (panelized_panel.root_vpath, TRUE);
 503     panelized_panel.root_vpath = vfs_path_clone (new_root);
 504 }
 505 
 506 /* --------------------------------------------------------------------------------------------- */
 507 
 508 void
 509 panelize_save_panel (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 510 {
 511     int i;
 512     dir_list *list = &panel->dir;
 513 
 514     panelize_change_root (current_panel->cwd_vpath);
 515 
 516     if (panelized_panel.list.len > 0)
 517         dir_list_clean (&panelized_panel.list);
 518     if (panel->dir.len == 0)
 519         return;
 520 
 521     if (panel->dir.len > panelized_panel.list.size)
 522         dir_list_grow (&panelized_panel.list, panel->dir.len - panelized_panel.list.size);
 523     panelized_panel.list.len = panel->dir.len;
 524 
 525     for (i = 0; i < panel->dir.len; i++)
 526     {
 527         panelized_panel.list.list[i].fname = mc_g_string_dup (list->list[i].fname);
 528         panelized_panel.list.list[i].f.link_to_dir = list->list[i].f.link_to_dir;
 529         panelized_panel.list.list[i].f.stale_link = list->list[i].f.stale_link;
 530         panelized_panel.list.list[i].f.dir_size_computed = list->list[i].f.dir_size_computed;
 531         panelized_panel.list.list[i].f.marked = list->list[i].f.marked;
 532         panelized_panel.list.list[i].st = list->list[i].st;
 533         panelized_panel.list.list[i].sort_key = list->list[i].sort_key;
 534         panelized_panel.list.list[i].second_sort_key = list->list[i].second_sort_key;
 535     }
 536 }
 537 
 538 /* --------------------------------------------------------------------------------------------- */
 539 
 540 /**
 541  * Conditionally switches a panel's directory to "/" (root).
 542  *
 543  * If a panelized panel's listing contain absolute paths, this function
 544  * sets the panel's directory to "/". Otherwise it does nothing.
 545  *
 546  * Rationale:
 547  *
 548  * This makes tokenized strings like "%d/%p" work. This also makes other
 549  * places work where such naive concatenation is done in code (e.g., when
 550  * pressing ctrl+shift+enter, for CK_PutCurrentFullSelected).
 551  *
 552  * When to call:
 553  *
 554  * You should always call this function after you populate the listing
 555  * of a panelized panel.
 556  */
 557 void
 558 panelize_absolutize_if_needed (WPanel * panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 559 {
 560     const dir_list *const list = &panel->dir;
 561 
 562     /* Note: We don't support mixing of absolute and relative paths, which is
 563      * why it's ok for us to check only the 1st entry. */
 564     if (list->len > 1 && g_path_is_absolute (list->list[1].fname->str))
 565     {
 566         vfs_path_t *root;
 567 
 568         root = vfs_path_from_str (PATH_SEP_STR);
 569         panel_set_cwd (panel, root);
 570         if (panel == current_panel)
 571             mc_chdir (root);
 572         vfs_path_free (root, TRUE);
 573     }
 574 }
 575 
 576 /* --------------------------------------------------------------------------------------------- */
 577 
 578 void
 579 cd_panelize_cmd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 580 {
 581     if (!SELECTED_IS_PANEL)
 582         create_panel (MENU_PANEL_IDX, view_listing);
 583 
 584     do_panelize_cd (PANEL (get_panel_widget (MENU_PANEL_IDX)));
 585 }
 586 
 587 /* --------------------------------------------------------------------------------------------- */
 588 
 589 void
 590 external_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 591 {
 592     if (!vfs_current_is_local ())
 593     {
 594         message (D_ERROR, MSG_ERROR, _("Cannot run external panelize in a non-local directory"));
 595         return;
 596     }
 597 
 598     init_panelize ();
 599 
 600     /* display file info */
 601     tty_setcolor (SELECTED_COLOR);
 602 
 603     switch (dlg_run (panelize_dlg))
 604     {
 605     case B_CANCEL:
 606         break;
 607 
 608     case B_ADD:
 609         add2panelize_cmd ();
 610         break;
 611 
 612     case B_REMOVE:
 613         {
 614             struct panelize *entry;
 615 
 616             listbox_get_current (l_panelize, NULL, (void **) &entry);
 617             remove_from_panelize (entry);
 618             break;
 619         }
 620 
 621     case B_ENTER:
 622         if (!input_is_empty (pname))
 623         {
 624             char *cmd;
 625 
 626             cmd = input_get_text (pname);
 627             widget_destroy (WIDGET (panelize_dlg));
 628             do_external_panelize (cmd);
 629             g_free (cmd);
 630             repaint_screen ();
 631             return;
 632         }
 633         break;
 634 
 635     default:
 636         break;
 637     }
 638 
 639     panelize_done ();
 640 }
 641 
 642 /* --------------------------------------------------------------------------------------------- */
 643 
 644 void
 645 load_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 646 {
 647     char **keys;
 648 
 649     keys = mc_config_get_keys (mc_global.main_config, panelize_section, NULL);
 650 
 651     add2panelize (g_strdup (_("Other command")), g_strdup (""));
 652 
 653     if (*keys == NULL)
 654     {
 655         add2panelize (g_strdup (_("Modified git files")), g_strdup ("git ls-files --modified"));
 656         add2panelize (g_strdup (_("Find rejects after patching")),
 657                       g_strdup ("find . -name \\*.rej -print"));
 658         add2panelize (g_strdup (_("Find *.orig after patching")),
 659                       g_strdup ("find . -name \\*.orig -print"));
 660         add2panelize (g_strdup (_("Find SUID and SGID programs")),
 661                       g_strdup
 662                       ("find . \\( \\( -perm -04000 -a -perm /011 \\) -o \\( -perm -02000 -a -perm /01 \\) \\) -print"));
 663     }
 664     else
 665     {
 666         GIConv conv;
 667         char **profile_keys;
 668 
 669         conv = str_crt_conv_from ("UTF-8");
 670 
 671         for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
 672         {
 673             GString *buffer;
 674 
 675             if (mc_global.utf8_display || conv == INVALID_CONV)
 676                 buffer = g_string_new (*profile_keys);
 677             else
 678             {
 679                 buffer = g_string_new ("");
 680                 if (str_convert (conv, *profile_keys, buffer) == ESTR_FAILURE)
 681                     g_string_assign (buffer, *profile_keys);
 682             }
 683 
 684             add2panelize (g_string_free (buffer, FALSE),
 685                           mc_config_get_string (mc_global.main_config, panelize_section,
 686                                                 *profile_keys, ""));
 687         }
 688 
 689         str_close_conv (conv);
 690     }
 691 
 692     g_strfreev (keys);
 693 }
 694 
 695 /* --------------------------------------------------------------------------------------------- */
 696 
 697 void
 698 save_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 699 {
 700     struct panelize *current;
 701 
 702     mc_config_del_group (mc_global.main_config, panelize_section);
 703 
 704     for (current = panelize; current != NULL; current = current->next)
 705         if (strcmp (current->label, _("Other command")) != 0)
 706             mc_config_set_string (mc_global.main_config,
 707                                   panelize_section, current->label, current->command);
 708 }
 709 
 710 /* --------------------------------------------------------------------------------------------- */
 711 
 712 void
 713 done_panelize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 714 {
 715     struct panelize *current, *next;
 716 
 717     for (current = panelize; current != NULL; current = next)
 718     {
 719         next = current->next;
 720         g_free (current->label);
 721         g_free (current->command);
 722         g_free (current);
 723     }
 724 }
 725 
 726 /* --------------------------------------------------------------------------------------------- */

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