Codepage messages related translated & other stuff...
[midnight-commander.git] / src / hotlist.c
blobd83a3836e5426df61ec1400d09be168ba3af1391
1 /* Directory hotlist -- for the Midnight Commander
2 Copyright (C) 1994, 1995, 1996, 1997 the Free Software Foundation.
4 Written by:
5 1994 Radek Doulik
6 1995 Janne Kukonlehto
7 1996 Andrej Borsenkow
8 1997 Norbert Warmuth
10 Janne did the original Hotlist code, Andrej made the groupable
11 hotlist; the move hotlist and revamped the file format and made
12 it stronger.
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
19 This program 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.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include <config.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include <string.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/stat.h>
39 #ifdef SCO_FLAVOR
40 # include <sys/timeb.h> /* alex: for struct timeb, used in time.h */
41 #endif /* SCO_FLAVOR */
42 #include <time.h>
43 #ifndef HAS_NO_GRP_PWD_H
44 # include <grp.h>
45 # include <pwd.h>
46 #endif
47 #ifdef NEEDS_IO_H
48 # include <io.h>
49 #endif
50 #include "tty.h"
51 #include "global.h"
52 #include "win.h"
53 #include "color.h"
54 #include "dlg.h"
55 #include "widget.h"
56 #include "dialog.h" /* For do_refresh() */
57 #include "setup.h" /* For profile_bname */
58 #include "profile.h" /* Load/save directories hotlist */
60 #include "../vfs/vfs.h"
61 /* Needed for the extern declarations of integer parameters */
62 #include "wtools.h"
63 #include "dir.h"
64 #include "panel.h" /* Needed for the externs */
65 #include "file.h"
66 #include "main.h"
67 #include "hotlist.h"
68 #include "key.h"
69 #include "command.h"
71 #define UX 5
72 #define UY 2
74 #define BX UX
75 #define BY LINES-6
77 #define BUTTONS (sizeof(hotlist_but)/sizeof(struct _hotlist_but))
78 #define LABELS 3
79 #define B_ADD_CURRENT B_USER
80 #define B_REMOVE (B_USER + 1)
81 #define B_NEW_GROUP (B_USER + 2)
82 #define B_NEW_ENTRY (B_USER + 3)
83 #define B_UP_GROUP (B_USER + 4)
84 #define B_INSERT (B_USER + 5)
85 #define B_APPEND (B_USER + 6)
86 #define B_MOVE (B_USER + 7)
88 static WListbox *l_hotlist;
89 static WListbox *l_movelist;
91 static Dlg_head *hotlist_dlg;
92 static Dlg_head *movelist_dlg;
94 static WLabel *pname, *pname_group, *movelist_group;
96 enum HotListType {
97 HL_TYPE_GROUP,
98 HL_TYPE_ENTRY,
99 HL_TYPE_COMMENT
102 static struct {
104 * these parameters are intended to be user configurable
106 int expanded; /* expanded view of all groups at startup */
109 * these reflect run time state
112 int loaded; /* hotlist is loaded */
113 int readonly; /* hotlist readonly */
114 int file_error; /* parse error while reading file */
115 int running; /* we are running dlg (and have to
116 update listbox */
117 int moving; /* we are in moving hotlist currently */
118 int modified; /* hotlist was modified */
119 int type; /* LIST_HOTLIST || LIST_VFSLIST */
120 } hotlist_state;
122 struct _hotlist_but {
123 int ret_cmd, flags, y, x;
124 char *text;
125 char *tkname;
126 int type;
127 } hotlist_but[] = {
128 { B_MOVE, NORMAL_BUTTON, 1, 42, N_("&Move"), "move", LIST_HOTLIST},
129 { B_REMOVE, NORMAL_BUTTON, 1, 30, N_("&Remove"), "r", LIST_HOTLIST},
130 { B_APPEND, NORMAL_BUTTON, 1, 15, N_("&Append"), "e", LIST_MOVELIST},
131 { B_INSERT, NORMAL_BUTTON, 1, 0, N_("&Insert"), "g", LIST_MOVELIST},
132 { B_NEW_ENTRY, NORMAL_BUTTON, 1, 15, N_("New &Entry"), "e", LIST_HOTLIST},
133 { B_NEW_GROUP, NORMAL_BUTTON, 1, 0, N_("New &Group"), "g", LIST_HOTLIST},
134 { B_CANCEL, NORMAL_BUTTON, 0, 53, N_("&Cancel"), "cc", LIST_HOTLIST|LIST_VFSLIST|LIST_MOVELIST},
135 { B_UP_GROUP, NORMAL_BUTTON, 0, 42, N_("&Up"), "up", LIST_HOTLIST|LIST_MOVELIST},
136 { B_ADD_CURRENT, NORMAL_BUTTON, 0, 20, N_("&Add current"),"ad", LIST_HOTLIST},
137 { B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("Change &To"), "ct", LIST_HOTLIST|LIST_VFSLIST|LIST_MOVELIST},
140 /* Directory hotlist */
141 static struct hotlist{
142 enum HotListType type;
143 char *directory;
144 char *label;
145 struct hotlist *head;
146 struct hotlist *up;
147 struct hotlist *next;
148 } *hotlist = NULL;
150 struct hotlist *current_group;
152 static void remove_from_hotlist (struct hotlist *entry);
153 void add_new_group_cmd (void);
155 #define new_hotlist() g_new0(struct hotlist, 1)
157 static void hotlist_refresh (Dlg_head *dlg)
159 dialog_repaint (dlg, COLOR_NORMAL, COLOR_HOT_NORMAL);
160 attrset (COLOR_NORMAL);
161 draw_box (dlg, 2, 5,
162 dlg->lines - (hotlist_state.moving ? 6 : 10),
163 dlg->cols - (UX*2));
164 if (!hotlist_state.moving)
165 draw_box (dlg, dlg->lines-8, 5, 3, dlg->cols - (UX*2));
168 /* If current->data is 0, then we are dealing with a VFS pathname */
169 static INLINE void update_path_name ()
171 char *text, *p;
172 WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
173 Dlg_head *dlg = hotlist_state.moving ? movelist_dlg : hotlist_dlg;
175 if (list->current){
176 if (list->current->data != 0) {
177 struct hotlist *hlp = (struct hotlist *)list->current->data;
179 if (hlp->type == HL_TYPE_ENTRY)
180 text = hlp->directory;
181 else
182 text = _("Subgroup - press ENTER to see list");
184 p = g_strconcat (" ", current_group->label, " ", NULL);
185 if (!hotlist_state.moving)
186 label_set_text (pname_group, name_trunc (p, dlg->cols - (UX*2+4)));
187 else
188 label_set_text (movelist_group, name_trunc (p, dlg->cols - (UX*2+4)));
189 g_free (p);
190 } else {
191 text = list->current->text;
193 } else {
194 text = "";
196 if (!hotlist_state.moving)
197 label_set_text (pname, name_trunc (text, dlg->cols - (UX*2+4)));
198 dlg_redraw (dlg);
201 #define CHECK_BUFFER \
202 do { \
203 int i; \
205 if ((i = strlen (current->label) + 3) > buflen) { \
206 g_free (buf); \
207 buf = g_malloc (buflen = 1024 * (i/1024 + 1)); \
209 buf[0] = '\0'; \
210 } while (0)
212 static void fill_listbox (void)
214 struct hotlist *current = current_group->head;
215 static char *buf;
216 static int buflen;
218 if (!buf)
219 buf = g_malloc (buflen = 1024);
220 buf[0] = '\0';
222 while (current){
223 switch (current->type) {
224 case HL_TYPE_GROUP:
226 CHECK_BUFFER;
227 strcat (strcat (buf, "->"), current->label);
228 if (hotlist_state.moving)
229 listbox_add_item (l_movelist, 0, 0, buf, current);
230 else
231 listbox_add_item (l_hotlist, 0, 0, buf, current);
233 break;
234 case HL_TYPE_ENTRY:
235 if (hotlist_state.moving)
236 listbox_add_item (l_movelist, 0, 0, current->label, current);
237 else
238 listbox_add_item (l_hotlist, 0, 0, current->label, current);
239 break;
240 default:
241 break;
243 current = current->next;
247 #undef CHECK_BUFFER
249 static void
250 unlink_entry (struct hotlist *entry)
252 struct hotlist *current = current_group->head;
254 if (current == entry)
255 current_group->head = entry->next;
256 else
257 while (current && current->next != entry)
258 current = current->next;
259 if (current)
260 current->next = entry->next;
261 entry->next =
262 entry->up = 0;
265 static void add_new_entry_cmd (void);
266 static void init_movelist (int, struct hotlist *);
268 static int hotlist_button_callback (int action, void *data)
270 switch (action) {
271 case B_MOVE:
273 struct hotlist *saved = current_group;
274 struct hotlist *item;
275 struct hotlist *moveto_item = 0;
276 struct hotlist *moveto_group = 0;
277 int ret;
279 if (!l_hotlist->current)
280 return 0; /* empty group - nothing to do */
281 item = l_hotlist->current->data;
282 hotlist_state.moving = 1;
283 init_movelist (LIST_MOVELIST, item);
284 run_dlg (movelist_dlg);
285 ret = movelist_dlg->ret_value;
286 hotlist_state.moving = 0;
287 if (l_movelist->current)
288 moveto_item = l_movelist->current->data;
289 moveto_group = current_group;
290 destroy_dlg (movelist_dlg);
291 current_group = saved;
292 if (ret == B_CANCEL)
293 return 0;
294 if (moveto_item == item)
295 return 0; /* If we insert/append a before/after a
296 it hardly changes anything ;) */
297 unlink_entry (item);
298 listbox_remove_current (l_hotlist, 1);
299 item->up = moveto_group;
300 if (!moveto_group->head)
301 moveto_group->head = item;
302 else if (!moveto_item) { /* we have group with just comments */
303 struct hotlist *p = moveto_group->head;
305 /* skip comments */
306 while (p->next)
307 p = p->next;
308 p->next = item;
309 } else if (ret == B_ENTER || ret == B_APPEND)
310 if (!moveto_item->next)
311 moveto_item->next = item;
312 else {
313 item->next = moveto_item->next;
314 moveto_item->next = item;
316 else if (moveto_group->head == moveto_item) {
317 moveto_group->head = item;
318 item->next = moveto_item;
319 } else {
320 struct hotlist *p = moveto_group->head;
322 while (p->next != moveto_item)
323 p = p->next;
324 item->next = p->next;
325 p->next = item;
327 listbox_remove_list (l_hotlist);
328 fill_listbox ();
329 repaint_screen ();
330 hotlist_state.modified = 1;
331 return 0;
332 break;
334 case B_REMOVE:
335 if (l_hotlist->current)
336 remove_from_hotlist (l_hotlist->current->data);
337 return 0;
338 break;
340 case B_NEW_GROUP:
341 add_new_group_cmd ();
342 return 0;
343 break;
345 case B_ADD_CURRENT:
346 add2hotlist_cmd ();
347 return 0;
348 break;
350 case B_NEW_ENTRY:
351 add_new_entry_cmd ();
352 return 0;
353 break;
355 case B_ENTER:
357 WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
358 if (list->current){
359 if (list->current->data) {
360 struct hotlist *hlp = (struct hotlist*) list->current->data;
361 if (hlp->type == HL_TYPE_ENTRY)
362 return 1;
363 else {
364 listbox_remove_list (list);
365 current_group = hlp;
366 fill_listbox ();
367 return 0;
369 } else
370 return 1;
373 /* Fall through if list empty - just go up */
375 case B_UP_GROUP:
377 WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
378 listbox_remove_list (list);
379 current_group = current_group->up;
380 fill_listbox ();
381 return 0;
382 break;
385 default:
386 return 1;
387 break;
392 static int hotlist_callback (Dlg_head * h, int Par, int Msg)
394 switch (Msg) {
395 case DLG_DRAW:
396 hotlist_refresh (h);
397 break;
399 case DLG_UNHANDLED_KEY:
400 switch (Par) {
401 case '\n':
402 if (ctrl_pressed())
403 goto l1;
404 case KEY_ENTER:
405 case KEY_RIGHT:
406 if (hotlist_button_callback (B_ENTER, 0)) {
407 h->ret_value = B_ENTER;
408 dlg_stop (h);
410 return 1;
411 break;
412 case KEY_LEFT:
413 if (hotlist_state.type != LIST_VFSLIST )
414 return !hotlist_button_callback (B_UP_GROUP, 0);
415 else
416 return 0;
417 break;
419 case ALT('\n'):
420 case ALT('\r'):
421 if (!hotlist_state.moving)
423 if (l_hotlist->current){
424 if (l_hotlist->current->data) {
425 struct hotlist *hlp = (struct hotlist*) l_hotlist->current->data;
426 if (hlp->type == HL_TYPE_ENTRY) {
427 char *tmp = g_strconcat ( "cd ", hlp->directory, NULL);
428 stuff (input_w (cmdline), tmp, 0);
429 g_free (tmp);
430 dlg_stop (h);
431 h->ret_value = B_CANCEL;
432 return 1;
437 return 1; /* ignore key */
438 default:
439 return 0;
441 break;
443 case DLG_POST_KEY:
444 if (hotlist_state.moving)
445 dlg_select_widget (movelist_dlg, l_movelist);
446 else
447 dlg_select_widget (hotlist_dlg, l_hotlist);
448 /* always stay on hotlist */
449 /* fall through */
451 case DLG_INIT:
452 attrset (MENU_ENTRY_COLOR);
453 update_path_name ();
454 break;
456 return 0;
459 static int l_call (void *l)
461 WListbox *list = (WListbox *) l;
462 Dlg_head *dlg = hotlist_state.moving ? movelist_dlg : hotlist_dlg;
464 if (list->current){
465 if (list->current->data) {
466 struct hotlist *hlp = (struct hotlist*) list->current->data;
467 if (hlp->type == HL_TYPE_ENTRY) {
468 dlg->ret_value = B_ENTER;
469 dlg_stop (dlg);
470 return listbox_finish;
471 } else {
472 hotlist_button_callback (B_ENTER, (void *)0);
473 hotlist_callback (dlg, '\n', DLG_POST_KEY);
474 return listbox_nothing;
476 } else {
477 dlg->ret_value = B_ENTER;
478 dlg_stop (dlg);
479 return listbox_finish;
483 hotlist_button_callback (B_UP_GROUP, (void *)0);
484 hotlist_callback (dlg, 'u', DLG_POST_KEY);
485 return listbox_nothing;
488 static void add_name_to_list (char *path)
490 listbox_add_item (l_hotlist, 0, 0, path, 0);
494 * Expands all button names (once) and recalculates button positions.
495 * returns number of columns in the dialog box, which is 10 chars longer
496 * then buttonbar.
498 * If common width of the window (i.e. in xterm) is less than returned
499 * width - sorry :) (anyway this did not handled in previous version too)
501 static int
502 init_i18n_stuff(int list_type, int cols)
504 register int i;
505 static char* cancel_but = "&Cancel";
507 #ifdef ENABLE_NLS
508 static int hotlist_i18n_flag = 0;
510 if (!hotlist_i18n_flag)
512 i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
513 while (i--)
514 hotlist_but [i].text = _(hotlist_but [i].text);
516 cancel_but = _(cancel_but);
517 hotlist_i18n_flag = 1;
519 #endif /* ENABLE_NLS */
521 /* Dynamic resizing of buttonbars */
523 int len[2], count[2]; /* at most two lines of buttons */
524 int cur_x[2], row;
526 i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
527 len[0] = len[1] = count[0] = count[1] = 0;
529 /* Count len of buttonbars, assuming 2 extra space between buttons */
530 while (i--)
532 if (! (hotlist_but[i].type & list_type))
533 continue;
535 row = hotlist_but [i].y;
536 ++count [row];
537 len [row] += strlen (hotlist_but [i].text) + 5;
538 if (hotlist_but [i].flags == DEFPUSH_BUTTON)
539 len [row] += 2;
541 len[0] -= 2;
542 len[1] -= 2;
544 cols = max(cols, max(len[0], len[1]));
546 /* arrange buttons */
548 cur_x[0] = cur_x[1] = 0;
549 i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
550 while (i--)
552 if (! (hotlist_but[i].type & list_type))
553 continue;
555 row = hotlist_but [i].y;
557 if (hotlist_but [i].x != 0)
559 /* not first int the row */
560 if (!strcmp (hotlist_but [i].text, cancel_but))
561 hotlist_but [i].x =
562 cols - strlen (hotlist_but [i].text) - 13;
563 else
564 hotlist_but [i].x = cur_x [row];
567 cur_x [row] += strlen (hotlist_but [i].text) + 2
568 + (hotlist_but [i].flags == DEFPUSH_BUTTON ? 5 : 3);
572 return cols;
575 static void init_hotlist (int list_type)
577 int i;
578 int hotlist_cols = init_i18n_stuff (list_type, COLS - 6);
580 do_refresh ();
582 hotlist_state.expanded = GetPrivateProfileInt ("HotlistConfig",
583 "expanded_view_of_groups", 0, profile_name);
585 hotlist_dlg = create_dlg (0, 0, LINES-2, hotlist_cols, dialog_colors,
586 hotlist_callback,
587 list_type == LIST_VFSLIST ? "[vfshot]" : "[Hotlist]",
588 list_type == LIST_VFSLIST ? "vfshot" : "hotlist",
589 DLG_CENTER|DLG_GRID);
590 x_set_dialog_title (hotlist_dlg,
591 list_type == LIST_VFSLIST ? _("Active VFS directories") : _("Directory hotlist"));
593 #define XTRACT(i) BY+hotlist_but[i].y, BX+hotlist_but[i].x, hotlist_but[i].ret_cmd, hotlist_but[i].flags, hotlist_but[i].text, hotlist_button_callback, 0, hotlist_but[i].tkname
595 for (i = 0; i < BUTTONS; i++){
596 if (hotlist_but[i].type & list_type)
597 add_widget (hotlist_dlg, button_new (XTRACT (i)));
599 #undef XTRACT
601 /* We add the labels.
602 * pname will hold entry's pathname;
603 * pname_group will hold name of current group
605 pname = label_new (UY-11+LINES, UX+2, "", "the-lab");
606 add_widget (hotlist_dlg, pname);
607 if (!hotlist_state.moving) {
608 add_widget (hotlist_dlg, label_new (UY-12+LINES, UX+1, _(" Directory path "), NULL));
610 /* This one holds the displayed pathname */
611 pname_group = label_new (UY, UX+1, _(" Directory label "), NULL);
612 add_widget (hotlist_dlg, pname_group);
614 /* get new listbox */
615 l_hotlist = listbox_new (UY + 1, UX + 1, COLS-2*UX-8, LINES-14, listbox_cback, l_call, "listbox");
617 /* Fill the hotlist with the active VFS or the hotlist */
618 if (list_type == LIST_VFSLIST){
619 listbox_add_item (l_hotlist, 0, 0, home_dir, 0);
620 vfs_fill_names (add_name_to_list);
621 } else
622 fill_listbox ();
624 add_widget (hotlist_dlg, l_hotlist);
625 /* add listbox to the dialogs */
628 static void init_movelist (int list_type, struct hotlist *item)
630 int i;
631 char *hdr = g_strconcat (_("Moving "), item->label, NULL);
632 int movelist_cols = init_i18n_stuff (list_type, COLS - 6);
634 do_refresh ();
636 movelist_dlg = create_dlg (0, 0, LINES-6, movelist_cols, dialog_colors,
637 hotlist_callback, "[Hotlist]",
638 "movelist",
639 DLG_CENTER|DLG_GRID);
640 x_set_dialog_title (movelist_dlg, hdr);
641 g_free (hdr);
643 #define XTRACT(i) BY-4+hotlist_but[i].y, BX+hotlist_but[i].x, hotlist_but[i].ret_cmd, hotlist_but[i].flags, hotlist_but[i].text, hotlist_button_callback, 0, hotlist_but[i].tkname
645 for (i = 0; i < BUTTONS; i++){
646 if (hotlist_but[i].type & list_type)
647 add_widget (movelist_dlg, button_new (XTRACT (i)));
650 #undef XTRACT
652 /* We add the labels. We are interested in the last one,
653 * that one will hold the path name label
655 movelist_group = label_new (UY, UX+1, _(" Directory label "), NULL);
656 add_widget (movelist_dlg, movelist_group);
657 /* get new listbox */
658 l_movelist = listbox_new (UY + 1, UX + 1,
659 movelist_dlg->cols - 2*UX - 2, movelist_dlg->lines - 8,
660 listbox_cback, l_call, "listbox");
662 fill_listbox ();
664 add_widget (movelist_dlg, l_movelist);
665 /* add listbox to the dialogs */
668 static void hotlist_done (void)
670 destroy_dlg (hotlist_dlg);
671 if (0)
672 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
673 repaint_screen ();
676 static char *
677 find_group_section (struct hotlist *grp)
679 return g_strconcat (grp->directory, ".Group", NULL);
684 /* 1.11.96 bor: added pos parameter to control placement of new item.
685 see widget.c, listbox_add_item()
686 now hotlist is in unsorted mode
688 static struct hotlist *
689 add2hotlist (char *label, char *directory, enum HotListType type, int pos)
691 struct hotlist *current;
692 struct hotlist *new;
694 if (l_hotlist && l_hotlist->current)
695 current = l_hotlist->current->data;
697 new = new_hotlist ();
699 new->type = type;
700 new->label = label;
701 new->directory = directory;
702 new->up = current_group;
704 if (!current_group->head) { /* first element in group */
705 current_group->head = new;
706 } else if (pos == 2) { /* should be appended after current*/
707 new->next = current->next;
708 current->next = new;
709 } else if (pos == 1 &&
710 current == current_group->head) {
711 /* should be inserted before first item */
712 new->next = current;
713 current_group->head = new;
714 } else if (pos == 1) { /* befor current */
715 struct hotlist *p = current_group->head;
717 while (p->next != current)
718 p = p->next;
720 new->next = current;
721 p->next = new;
722 } else { /* append at the end */
723 struct hotlist *p = current_group->head;
725 while (p->next)
726 p = p->next;
728 p->next = new;
731 if (hotlist_state.running && type != HL_TYPE_COMMENT) {
732 if (type == HL_TYPE_GROUP) {
733 char *lbl = g_strconcat ("->", new->label, NULL);
735 listbox_add_item (l_hotlist, pos, 0, lbl, new);
736 g_free (lbl);
737 } else
738 listbox_add_item (l_hotlist, pos, 0, new->label, new);
739 listbox_select_entry (l_hotlist, l_hotlist->current);
741 return new;
746 * Support routine for add_new_entry_input()/add_new_group_input()
747 * Change positions of buttons (first three widgets).
749 * This is just a quick hack. Accurate procedure must take care of
750 * internationalized label lengths and total buttonbar length...assume
751 * 64 is longer anyway.
753 static void add_widgets_i18n(QuickWidget* qw, int len)
755 int i, l[3], space, cur_x;
757 for (i = 0; i < 3; i++)
759 qw [i].text = _(qw [i].text);
760 l[i] = strlen (qw [i].text) + 3;
762 space = (len - 4 - l[0] - l[1] - l[2]) / 4;
764 for (cur_x = 2 + space, i = 3; i--; cur_x += l[i] + space)
766 qw [i].relative_x = cur_x;
767 qw [i].x_divisions = len;
771 static int add_new_entry_input (char *header, char *text1, char *text2, char *help, char **r1, char **r2)
773 #define RELATIVE_Y_BUTTONS 4
774 #define RELATIVE_Y_LABEL_PTH 3
775 #define RELATIVE_Y_INPUT_PTH 4
777 QuickDialog Quick_input;
778 static QuickWidget quick_widgets [] = {
779 { quick_button, 55, 80, RELATIVE_Y_BUTTONS, 0, N_("&Cancel"), 0, B_CANCEL,
780 0, 0, "button-cancel" },
781 { quick_button, 30, 80, RELATIVE_Y_BUTTONS, 0, N_("&Insert"), 0, B_INSERT,
782 0, 0, "button-insert" },
783 { quick_button, 10, 80, RELATIVE_Y_BUTTONS, 0, N_("&Append"), 0, B_APPEND,
784 0, 0, "button-append" },
785 { quick_input, 4, 80, RELATIVE_Y_INPUT_PTH, 0, "",58, 0,
786 0, 0, "input-pth" },
787 { quick_label, RELATIVE_Y_LABEL_PTH, 80, 3, 0, 0, 0, 0,
788 0, 0, "label-pth" },
789 { quick_input, 4, 80, 3, 0, "", 58, 0,
790 0, 0, "input-lbl" },
791 { quick_label, 3, 80, 2, 0, 0, 0, 0,
792 0, 0, "label-lbl" },
793 { 0 } };
795 int len;
796 int i;
797 int lines1, lines2;
798 char *my_str1, *my_str2;
800 #ifdef ENABLE_NLS
801 static int i18n_flag = 0;
802 #endif /* ENABLE_NLS */
804 len = max (strlen (header), msglen (text1, &lines1));
805 len = max (len, msglen (text2, &lines2)) + 4;
806 len = max (len, 64);
808 #ifdef ENABLE_NLS
809 if (!i18n_flag)
811 add_widgets_i18n(quick_widgets, len);
812 i18n_flag = 1;
814 #endif /* ENABLE_NLS */
816 Quick_input.xlen = len;
817 Quick_input.xpos = -1;
818 Quick_input.title = header;
819 Quick_input.help = help;
820 Quick_input.class = "hotlist_new_entry";
821 Quick_input.i18n = 0;
822 quick_widgets [6].text = text1;
823 quick_widgets [4].text = text2;
824 quick_widgets [5].text = *r1;
825 quick_widgets [3].text = *r2;
827 for (i = 0; i < 7; i++)
828 quick_widgets [i].y_divisions = lines1+lines2+7;
829 Quick_input.ylen = lines1 + lines2 + 7;
831 quick_widgets [0].relative_y = RELATIVE_Y_BUTTONS + (lines1 + lines2);
832 quick_widgets [1].relative_y = RELATIVE_Y_BUTTONS + (lines1 + lines2);
833 quick_widgets [2].relative_y = RELATIVE_Y_BUTTONS + (lines1 + lines2);
834 quick_widgets [3].relative_y = RELATIVE_Y_INPUT_PTH + (lines1);
835 quick_widgets [4].relative_y = RELATIVE_Y_LABEL_PTH + (lines1);
837 quick_widgets [5].str_result = &my_str1;
838 quick_widgets [3].str_result = &my_str2;
840 Quick_input.widgets = quick_widgets;
841 if ((i = quick_dialog (&Quick_input)) != B_CANCEL){
842 *r1 = *(quick_widgets [5].str_result);
843 *r2 = *(quick_widgets [3].str_result);
844 return i;
845 } else
846 return 0;
849 static void add_new_entry_cmd (void)
851 char *title = 0, *url = 0;
852 int ret;
854 /* Take current directory as default value for input fields */
855 title = url = cpanel->cwd;
857 ret = add_new_entry_input (_("New hotlist entry"), _("Directory label"), _("Directory path"),
858 "[Hotlist]", &title, &url);
860 if (!ret || !title || !*title || !url || !*url)
861 return;
863 if (ret == B_ENTER || ret == B_APPEND)
864 add2hotlist (g_strdup (title),g_strdup (url), HL_TYPE_ENTRY, 2);
865 else
866 add2hotlist (g_strdup (title),g_strdup (url), HL_TYPE_ENTRY, 1);
868 hotlist_state.modified = 1;
871 static int add_new_group_input (char *header, char *label, char **result)
873 int ret;
874 QuickDialog Quick_input;
875 static QuickWidget quick_widgets [] = {
876 { quick_button, 55, 80, 1, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
877 "button-cancel" },
878 { quick_button, 30, 80, 1, 0, N_("&Insert"), 0, B_INSERT, 0, 0,
879 "button-insert" },
880 { quick_button, 10, 80, 1, 0, N_("&Append"), 0, B_APPEND, 0, 0,
881 "button-append" },
882 { quick_input, 4, 80, 0, 0, "", 58, 0, 0, 0, "input" },
883 { quick_label, 3, 80, 2, 0, 0, 0, 0, 0, 0, "label" },
884 { 0 } };
885 int relative_y[] = {1, 1, 1, 0, 2}; /* the relative_x component from the
886 quick_widgets variable above */
887 int len;
888 int i;
889 int lines;
890 char *my_str;
892 #ifdef ENABLE_NLS
893 static int i18n_flag = 0;
894 #endif /* ENABLE_NLS */
896 len = max (strlen (header), msglen (label, &lines)) + 4;
897 len = max (len, 64);
899 #ifdef ENABLE_NLS
900 if (!i18n_flag)
902 add_widgets_i18n(quick_widgets, len);
903 i18n_flag = 1;
905 #endif /* ENABLE_NLS */
907 Quick_input.xlen = len;
908 Quick_input.xpos = -1;
909 Quick_input.title = header;
910 Quick_input.help = "[Hotlist]";
911 Quick_input.class = "hotlist_new_group";
912 Quick_input.i18n = 0;
913 quick_widgets [4].text = label;
915 for (i = 0; i < 5; i++)
916 quick_widgets [i].y_divisions = lines+6;
917 Quick_input.ylen = lines + 6;
919 for (i = 0; i < 4; i++)
920 quick_widgets [i].relative_y = relative_y[i] + 2 + lines;
922 quick_widgets [3].str_result = &my_str;
923 quick_widgets [3].text = "";
925 Quick_input.widgets = quick_widgets;
926 if ((ret = quick_dialog (&Quick_input)) != B_CANCEL){
927 *result = *(quick_widgets [3].str_result);
928 return ret;
929 } else
930 return 0;
933 void add_new_group_cmd (void)
935 char *label;
936 int ret;
938 ret = add_new_group_input (_(" New hotlist group "), _("Name of new group"), &label);
939 if (!ret || !label || !*label)
940 return;
942 if (ret == B_ENTER || ret == B_APPEND)
943 add2hotlist (label, 0, HL_TYPE_GROUP, 2);
944 else
945 add2hotlist (label, 0, HL_TYPE_GROUP, 1);
947 hotlist_state.modified = 1;
950 void add2hotlist_cmd (void)
952 char *prompt, *label;
953 char *cp = _("Label for \"%s\":");
954 int l = strlen (cp);
956 prompt = g_strdup_printf (cp, name_trunc (cpanel->cwd, COLS-2*UX-(l+8)));
957 label = input_dialog (_(" Add to hotlist "), prompt, cpanel->cwd);
958 g_free (prompt);
959 if (!label || !*label)
960 return;
962 add2hotlist (label,g_strdup (cpanel->cwd), HL_TYPE_ENTRY, 0);
963 hotlist_state.modified = 1;
966 static void remove_group (struct hotlist *grp)
968 struct hotlist *current = grp->head;
970 while (current) {
971 struct hotlist *next = current->next;
973 if (current->type == HL_TYPE_GROUP)
974 remove_group (current);
976 if (current->label)
977 g_free (current->label);
978 if (current->directory)
979 g_free (current->directory);
980 g_free (current);
982 current = next;
987 static void remove_from_hotlist (struct hotlist *entry)
989 if (entry->type == HL_TYPE_GROUP) {
990 if (entry->head) {
991 char *header;
992 int result;
994 header = g_strconcat (_(" Remove: "),
995 name_trunc (entry->label, 30),
996 " ",
997 NULL);
998 result = query_dialog (header, _("\n Group not empty.\n Remove it?"),
999 D_ERROR, 2,
1000 _("&No"), _("&Yes"));
1001 g_free (header);
1003 if (!result)
1004 return;
1007 remove_group (entry);
1010 unlink_entry (entry);
1012 if (entry->label)
1013 g_free (entry->label);
1014 if (entry->directory)
1015 g_free (entry->directory);
1016 g_free (entry);
1017 /* now remove list entry from screen */
1018 listbox_remove_current (l_hotlist, 1);
1019 hotlist_state.modified = 1;
1022 char *hotlist_cmd (int vfs_or_hotlist)
1024 char *target = NULL;
1026 hotlist_state.type = vfs_or_hotlist;
1027 load_hotlist ();
1029 init_hotlist (vfs_or_hotlist);
1031 /* display file info */
1032 attrset (SELECTED_COLOR);
1034 hotlist_state.running = 1;
1035 run_dlg (hotlist_dlg);
1036 hotlist_state.running = 0;
1037 save_hotlist ();
1039 switch (hotlist_dlg->ret_value) {
1040 case B_CANCEL:
1041 break;
1043 case B_ENTER:
1044 if (l_hotlist->current->data) {
1045 struct hotlist *hlp = (struct hotlist*) l_hotlist->current->data;
1046 target = g_strdup (hlp->directory);
1047 } else
1048 target = g_strdup (l_hotlist->current->text);
1049 break;
1052 hotlist_done ();
1053 return target;
1056 static void
1057 load_group (struct hotlist *grp)
1059 void *profile_keys;
1060 char *key, *value;
1061 char *group_section;
1062 struct hotlist *current = 0;
1064 group_section = find_group_section (grp);
1066 profile_keys = profile_init_iterator (group_section, profile_name);
1068 current_group = grp;
1070 while (profile_keys){
1071 profile_keys = profile_iterator_next (profile_keys, &key, &value);
1072 add2hotlist (g_strdup (value), g_strdup (key), HL_TYPE_GROUP, 0);
1074 g_free (group_section);
1076 profile_keys = profile_init_iterator (grp->directory, profile_name);
1078 while (profile_keys){
1079 profile_keys = profile_iterator_next (profile_keys, &key, &value);
1080 add2hotlist (g_strdup (value),g_strdup (key), HL_TYPE_ENTRY, 0);
1083 for (current = grp->head; current; current = current->next)
1084 load_group (current);
1087 #define TKN_GROUP 0
1088 #define TKN_ENTRY 1
1089 #define TKN_STRING 2
1090 #define TKN_URL 3
1091 #define TKN_ENDGROUP 4
1092 #define TKN_COMMENT 5
1093 #define TKN_EOL 125
1094 #define TKN_EOF 126
1095 #define TKN_UNKNOWN 127
1097 static char *tkn_buf;
1098 static int tkn_buf_length;
1099 static int tkn_length;
1101 static char *hotlist_file_name;
1102 static FILE *hotlist_file;
1103 static time_t hotlist_file_mtime;
1105 static int hot_skip_blanks ()
1107 int c;
1109 while ((c = getc (hotlist_file)) != EOF && c != '\n' && isspace (c))
1111 return c;
1115 static int hot_next_token ()
1117 int c;
1119 #define CHECK_BUF() \
1120 do { \
1121 if (tkn_length == tkn_buf_length) \
1122 tkn_buf = tkn_buf ? ( g_realloc (tkn_buf, tkn_buf_length += 1024)) \
1123 : ( g_malloc (tkn_buf_length = 1024)); \
1124 } while (0)
1126 tkn_length = 0;
1128 again:
1129 c = hot_skip_blanks ();
1130 switch (c) {
1131 case EOF:
1132 return TKN_EOF;
1133 break;
1134 case '\n':
1135 return TKN_EOL;
1136 break;
1137 case '#':
1138 while ((c = getc (hotlist_file)) != EOF && c != '\n') {
1139 if (c == EOF)
1140 return TKN_EOF;
1141 if (c != '\n') {
1142 CHECK_BUF();
1143 tkn_buf[tkn_length++] = c == '\n' ? ' ' : c;
1146 CHECK_BUF();
1147 tkn_buf[tkn_length] = '\0';
1148 return TKN_COMMENT;
1149 break;
1150 case '"':
1151 while ((c = getc (hotlist_file)) != EOF && c != '"') {
1152 if (c == '\\')
1153 if ((c = getc (hotlist_file)) == EOF)
1154 return TKN_EOF;
1155 CHECK_BUF();
1156 tkn_buf[tkn_length++] = c == '\n' ? ' ' : c;
1158 if (c == EOF)
1159 return TKN_EOF;
1160 CHECK_BUF();
1161 tkn_buf[tkn_length] = '\0';
1162 return TKN_STRING;
1163 break;
1164 case '\\':
1165 if ((c = getc (hotlist_file)) == EOF)
1166 return TKN_EOF;
1167 if (c == '\n')
1168 goto again;
1170 /* fall through; it is taken as normal character */
1172 default:
1173 do {
1174 CHECK_BUF();
1175 tkn_buf[tkn_length++] = toupper(c);
1176 } while ((c = fgetc (hotlist_file)) != EOF && isalnum (c));
1177 if (c != EOF)
1178 ungetc (c, hotlist_file);
1179 CHECK_BUF();
1180 tkn_buf[tkn_length] = '\0';
1181 if (strncmp (tkn_buf, "GROUP", tkn_length) == 0)
1182 return TKN_GROUP;
1183 else if (strncmp (tkn_buf, "ENTRY", tkn_length) == 0)
1184 return TKN_ENTRY;
1185 else if (strncmp (tkn_buf, "ENDGROUP", tkn_length) == 0)
1186 return TKN_ENDGROUP;
1187 else if (strncmp (tkn_buf, "URL", tkn_length) == 0)
1188 return TKN_URL;
1189 else
1190 return TKN_UNKNOWN;
1191 break;
1195 #define SKIP_TO_EOL { \
1196 int _tkn; \
1197 while ((_tkn = hot_next_token ()) != TKN_EOF && _tkn != TKN_EOL) ; \
1200 #define CHECK_TOKEN(_TKN_) \
1201 if ((tkn = hot_next_token ()) != _TKN_) { \
1202 hotlist_state.readonly = 1; \
1203 hotlist_state.file_error = 1; \
1204 while (tkn != TKN_EOL && tkn != TKN_EOF) \
1205 tkn = hot_next_token (); \
1206 break; \
1209 static void
1210 hot_load_group (struct hotlist * grp)
1212 int tkn;
1213 struct hotlist *new_grp;
1214 char *label, *url;
1216 current_group = grp;
1218 while ((tkn = hot_next_token()) != TKN_ENDGROUP)
1219 switch (tkn) {
1220 case TKN_GROUP:
1221 CHECK_TOKEN(TKN_STRING);
1222 new_grp = add2hotlist (g_strdup (tkn_buf), 0, HL_TYPE_GROUP, 0);
1223 SKIP_TO_EOL;
1224 hot_load_group (new_grp);
1225 current_group = grp;
1226 break;
1227 case TKN_ENTRY:
1228 CHECK_TOKEN(TKN_STRING);
1229 label = g_strdup (tkn_buf);
1230 CHECK_TOKEN(TKN_URL);
1231 CHECK_TOKEN(TKN_STRING);
1232 url = g_strdup (tkn_buf);
1233 add2hotlist (label, url, HL_TYPE_ENTRY, 0);
1234 SKIP_TO_EOL;
1235 break;
1236 case TKN_COMMENT:
1237 label = g_strdup (tkn_buf);
1238 add2hotlist (label, 0, HL_TYPE_COMMENT, 0);
1239 break;
1240 case TKN_EOF:
1241 hotlist_state.readonly = 1;
1242 hotlist_state.file_error = 1;
1243 return;
1244 break;
1245 case TKN_EOL:
1246 /* skip empty lines */
1247 break;
1248 default:
1249 hotlist_state.readonly = 1;
1250 hotlist_state.file_error = 1;
1251 SKIP_TO_EOL;
1252 break;
1254 SKIP_TO_EOL;
1257 static void
1258 hot_load_file (struct hotlist * grp)
1260 int tkn;
1261 struct hotlist *new_grp;
1262 char *label, *url;
1264 current_group = grp;
1266 while ((tkn = hot_next_token())!= TKN_EOF)
1267 switch (tkn) {
1268 case TKN_GROUP:
1269 CHECK_TOKEN(TKN_STRING);
1270 new_grp = add2hotlist (g_strdup (tkn_buf), 0, HL_TYPE_GROUP, 0);
1271 SKIP_TO_EOL;
1272 hot_load_group (new_grp);
1273 current_group = grp;
1274 break;
1275 case TKN_ENTRY:
1276 CHECK_TOKEN(TKN_STRING);
1277 label = g_strdup (tkn_buf);
1278 CHECK_TOKEN(TKN_URL);
1279 CHECK_TOKEN(TKN_STRING);
1280 url = g_strdup (tkn_buf);
1281 add2hotlist (label, url, HL_TYPE_ENTRY, 0);
1282 SKIP_TO_EOL;
1283 break;
1284 case TKN_COMMENT:
1285 label = g_strdup (tkn_buf);
1286 add2hotlist (label, 0, HL_TYPE_COMMENT, 0);
1287 break;
1288 case TKN_EOL:
1289 /* skip empty lines */
1290 break;
1291 default:
1292 hotlist_state.readonly = 1;
1293 hotlist_state.file_error = 1;
1294 SKIP_TO_EOL;
1295 break;
1299 static void
1300 clean_up_hotlist_groups (char *section)
1302 char *grp_section;
1303 void *profile_keys;
1304 char *key, *value;
1306 grp_section = g_strconcat (section, ".Group", NULL);
1307 if (profile_has_section (section, profile_name))
1308 profile_clean_section (section, profile_name);
1309 if (profile_has_section (grp_section, profile_name)) {
1310 profile_keys = profile_init_iterator (grp_section, profile_name);
1312 while (profile_keys) {
1313 profile_keys = profile_iterator_next (profile_keys, &key, &value);
1314 clean_up_hotlist_groups (key);
1316 profile_clean_section (grp_section, profile_name);
1318 g_free (grp_section);
1323 void load_hotlist (void)
1325 char *grp_section;
1326 int has_old_list = 0;
1327 int remove_old_list = 0;
1328 struct stat stat_buf;
1330 if (hotlist_state.loaded) {
1331 stat (hotlist_file_name, &stat_buf);
1332 if (hotlist_file_mtime < stat_buf.st_mtime)
1333 done_hotlist ();
1334 else
1335 return;
1338 if (!hotlist_file_name)
1339 hotlist_file_name = concat_dir_and_file (home_dir, HOTLIST_FILENAME);
1341 hotlist = new_hotlist ();
1342 hotlist->type = HL_TYPE_GROUP;
1343 hotlist->label = g_strdup (_(" Top level group "));
1344 hotlist->up = hotlist;
1346 * compatibility :-(
1348 hotlist->directory = g_strdup ("Hotlist");
1350 grp_section = g_strconcat ("Hotlist", ".Group", NULL);
1351 has_old_list = profile_has_section ("Hotlist", profile_name) ||
1352 profile_has_section (grp_section, profile_name);
1353 g_free (grp_section);
1355 if ((hotlist_file = fopen (hotlist_file_name, "r")) == 0) {
1356 int result;
1357 char *msg;
1359 msg = g_strconcat (_("Hotlist is now kept in file ~/"),
1360 HOTLIST_FILENAME, "\n",
1361 _("MC will load hotlist from ~/"),
1362 PROFILE_NAME, "\n",
1363 _("and then delete [Hotlist] section there"),
1364 NULL);
1365 message (0, _(" Hotlist Load "), msg);
1366 g_free (msg);
1368 load_group (hotlist);
1369 hotlist_state.loaded = 1;
1371 * just to be sure we got copy
1373 hotlist_state.modified = 1;
1374 result = save_hotlist ();
1375 hotlist_state.modified = 0;
1376 if (result) {
1377 remove_old_list = 1;
1378 } else {
1379 char *msg;
1381 msg = g_strconcat (_("MC was unable to write ~/"), HOTLIST_FILENAME,
1382 _(" file, your old hotlist entries were not deleted"), NULL);
1384 message (D_ERROR, _(" Hotlist Load "), msg);
1385 g_free (msg);
1387 } else {
1388 hot_load_file (hotlist);
1389 fclose (hotlist_file);
1390 hotlist_state.loaded = 1;
1391 if (has_old_list) {
1392 int result;
1393 char *msg;
1395 msg = g_strconcat (
1396 _("You have ~/"), HOTLIST_FILENAME, _(" file and [Hotlist] section in ~/"), PROFILE_NAME, "\n",
1397 _("Your ~/"), HOTLIST_FILENAME, _(" most probably was created\n"),
1398 _("by an earlier development version of MC\nand is more actual than ~/"),
1399 PROFILE_NAME, _(" entries\n\n"),
1400 _("You can choose between\n\n"
1401 " Remove - remove old hotlist entries from ~/"), PROFILE_NAME, "\n",
1402 _(" Keep - keep your old entries; you will be asked\n"
1403 " the same question next time\n"
1404 " Merge - add old entries to hotlist as group \"Entries from ~/"),
1405 PROFILE_NAME, "\"\n\n", NULL);
1407 result = query_dialog (_(" Hotlist Load "),
1408 msg, D_ERROR, 3, _("&Remove"), _("&Keep"), _("&Merge"));
1409 if (result == 0)
1410 remove_old_list = 1;
1411 else if (result == 2) {
1412 struct hotlist *grp = hotlist->head;
1413 struct hotlist *old;
1415 hotlist->head = 0;
1416 load_group (hotlist);
1418 old = new_hotlist ();
1419 old->type = HL_TYPE_GROUP;
1420 old->label = g_strconcat (_(" Entries from ~/"), PROFILE_NAME, NULL);
1421 old->up = hotlist;
1422 old->head = hotlist->head;
1423 old->next = grp;
1424 hotlist->head = old;
1425 hotlist_state.modified = 1;
1426 if (!save_hotlist ()){
1427 char *str;
1429 str = g_strconcat (_("MC was unable to write ~/"), HOTLIST_FILENAME,
1430 _(" file your old hotlist entries were not deleted"), NULL);
1432 message (D_ERROR, _(" Hotlist Load "), str);
1433 g_free (str);
1434 } else
1435 remove_old_list = 1;
1436 hotlist_state.modified = 0;
1441 if (remove_old_list) {
1442 clean_up_hotlist_groups ("Hotlist");
1443 sync_profiles ();
1446 stat (hotlist_file_name, &stat_buf);
1447 hotlist_file_mtime = stat_buf.st_mtime;
1448 current_group = hotlist;
1451 static void
1452 save_group (struct hotlist *grp)
1454 struct hotlist *current = grp->head;
1455 char *group_section;
1457 group_section = find_group_section (grp);
1459 profile_clean_section (group_section, profile_name);
1460 for (;current && current->type == HL_TYPE_GROUP; current = current->next){
1461 WritePrivateProfileString (group_section,
1462 current->directory,
1463 current->label,
1464 profile_name);
1466 g_free (group_section);
1468 for (current = grp->head;
1469 current && current->type == HL_TYPE_GROUP;
1470 current = current->next)
1471 save_group (current);
1473 profile_clean_section (grp->directory, profile_name);
1474 for (;current; current = current->next){
1475 WritePrivateProfileString (grp->directory,
1476 current->directory,
1477 current->label,
1478 profile_name);
1482 static int list_level = 0;
1484 static void
1485 hot_save_group (struct hotlist *grp)
1487 struct hotlist *current = grp->head;
1488 int i;
1489 char *s;
1491 #define INDENT(n) \
1492 do { \
1493 for (i = 0; i < n; i++) \
1494 putc (' ', hotlist_file); \
1495 } while (0)
1497 for (;current; current = current->next)
1498 switch (current->type) {
1499 case HL_TYPE_GROUP:
1500 INDENT (list_level);
1501 fputs ("GROUP \"", hotlist_file);
1502 for (s = current->label; *s; s++) {
1503 if (*s == '"')
1504 putc ('\\', hotlist_file);
1505 else if (*s == '\\')
1506 putc ('\\', hotlist_file);
1507 putc (*s, hotlist_file);
1509 fputs ("\"\n", hotlist_file);
1510 list_level += 2;
1511 hot_save_group (current);
1512 list_level -= 2;
1513 INDENT (list_level);
1514 fputs ("ENDGROUP\n", hotlist_file);
1515 break;
1516 case HL_TYPE_ENTRY:
1517 INDENT(list_level);
1518 fputs ("ENTRY \"", hotlist_file);
1519 for (s = current->label; *s; s++) {
1520 if (*s == '"')
1521 putc ('\\', hotlist_file);
1522 else if (*s == '\\')
1523 putc ('\\', hotlist_file);
1524 putc (*s, hotlist_file);
1526 fputs ("\" URL \"", hotlist_file);
1527 for (s = current->directory; *s; s++) {
1528 if (*s == '"')
1529 putc ('\\', hotlist_file);
1530 else if (*s == '\\')
1531 putc ('\\', hotlist_file);
1532 putc (*s, hotlist_file);
1534 fputs ("\"\n", hotlist_file);
1535 break;
1536 case HL_TYPE_COMMENT:
1537 fprintf (hotlist_file, "#%s\n", current->label);
1538 break;
1543 int save_hotlist (void)
1545 int saved = 0;
1546 struct stat stat_buf;
1548 if (!hotlist_state.readonly && hotlist_state.modified && hotlist_file_name) {
1549 char *fbak = g_strconcat (hotlist_file_name, ".bak", NULL);
1551 rename (hotlist_file_name, fbak);
1552 if ((hotlist_file = fopen (hotlist_file_name, "w")) != 0) {
1553 if (stat (fbak, &stat_buf) == 0)
1554 chmod (hotlist_file_name, stat_buf.st_mode);
1555 else
1556 chmod (hotlist_file_name, S_IRUSR | S_IWUSR);
1557 hot_save_group (hotlist);
1558 fclose (hotlist_file);
1559 stat (hotlist_file_name, &stat_buf);
1560 hotlist_file_mtime = stat_buf.st_mtime;
1561 saved = 1;
1562 hotlist_state.modified = 0;
1563 } else
1564 rename (fbak, hotlist_file_name);
1565 g_free (fbak);
1568 return saved;
1571 void done_hotlist (void)
1573 if (hotlist){
1574 remove_group (hotlist);
1575 if (hotlist->label)
1576 g_free (hotlist->label);
1577 if (hotlist->directory)
1578 g_free (hotlist->directory);
1579 g_free (hotlist);
1580 hotlist = 0;
1583 hotlist_state.loaded = 0;
1585 if (hotlist_file_name){
1586 g_free (hotlist_file_name);
1587 hotlist_file_name = 0;
1589 l_hotlist = 0;
1590 current_group = 0;
1591 if (tkn_buf){
1592 g_free (tkn_buf);
1593 tkn_buf_length = 0;
1594 tkn_length = 0;
1595 tkn_buf = NULL;