4 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2007, 2009, 2011
6 The Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995, 1996
10 Janne Kukonlehto, 1994, 1995, 1996
11 Dugan Porter, 1994, 1995, 1996
12 Jakub Jelinek, 1994, 1995, 1996
13 Mauricio Plaza, 1994, 1995, 1996
15 This file is part of the Midnight Commander.
17 The Midnight Commander is free software: you can redistribute it
18 and/or modify it under the terms of the GNU General Public License as
19 published by the Free Software Foundation, either version 3 of the License,
20 or (at your option) any later version.
22 The Midnight Commander is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 * \brief Source: various utilities
45 #include <sys/types.h>
49 #include "lib/global.h"
50 #include "lib/mcconfig.h"
51 #include "lib/fileloc.h"
52 #include "lib/vfs/vfs.h"
53 #include "lib/strutil.h"
56 /*** global variables ****************************************************************************/
58 /*** file scope macro definitions ****************************************************************/
60 #define ismode(n,m) ((n & m) == m)
62 /* Number of attempts to create a temporary file */
67 #define TMP_SUFFIX ".tmp"
69 #define ASCII_A (0x40 + 1)
70 #define ASCII_Z (0x40 + 26)
71 #define ASCII_a (0x60 + 1)
72 #define ASCII_z (0x60 + 26)
74 /*** file scope type declarations ****************************************************************/
76 /*** file scope variables ************************************************************************/
78 /*** file scope functions ************************************************************************/
79 /* --------------------------------------------------------------------------------------------- */
82 is_7bit_printable (unsigned char c
)
84 return (c
> 31 && c
< 127);
87 /* --------------------------------------------------------------------------------------------- */
90 is_iso_printable (unsigned char c
)
92 return ((c
> 31 && c
< 127) || c
>= 160);
95 /* --------------------------------------------------------------------------------------------- */
98 is_8bit_printable (unsigned char c
)
100 /* "Full 8 bits output" doesn't work on xterm */
101 if (mc_global
.tty
.xterm_flag
)
102 return is_iso_printable (c
);
104 return (c
> 31 && c
!= 127 && c
!= 155);
107 /* --------------------------------------------------------------------------------------------- */
110 resolve_symlinks (const vfs_path_t
* vpath
)
113 char *buf
, *buf2
, *q
, *r
, c
;
119 p
= p2
= vfs_path_to_str (vpath
);
120 r
= buf
= g_malloc (MC_MAXPATHLEN
);
121 buf2
= g_malloc (MC_MAXPATHLEN
);
127 q
= strchr (p
+ 1, PATH_SEP
);
130 q
= strchr (p
+ 1, 0);
136 if (mc_lstat (vpath
, &mybuf
) < 0)
142 if (!S_ISLNK (mybuf
.st_mode
))
148 len
= mc_readlink (vpath
, buf2
, MC_MAXPATHLEN
- 1);
156 if (*buf2
== PATH_SEP
)
161 canonicalize_pathname (buf
);
163 if (!*r
|| *(r
- 1) != PATH_SEP
)
164 /* FIXME: this condition is always true because r points to the EOL */
175 strcpy (buf
, PATH_SEP_STR
);
176 else if (*(r
- 1) == PATH_SEP
&& r
!= buf
+ 1)
185 /* --------------------------------------------------------------------------------------------- */
188 mc_util_write_backup_content (const char *from_file_name
, const char *to_file_name
)
193 gboolean ret1
= TRUE
;
195 if (!g_file_get_contents (from_file_name
, &contents
, &length
, NULL
))
198 backup_fd
= fopen (to_file_name
, "w");
199 if (backup_fd
== NULL
)
205 if (fwrite ((const void *) contents
, 1, length
, backup_fd
) != length
)
209 ret2
= fflush (backup_fd
);
210 ret2
= fclose (backup_fd
);
217 /* --------------------------------------------------------------------------------------------- */
218 /*** public functions ****************************************************************************/
219 /* --------------------------------------------------------------------------------------------- */
227 /* "Display bits" is ignored, since the user controls the output
228 by setting the output codepage */
229 return is_8bit_printable (c
);
231 if (!mc_global
.eight_bit_clean
)
232 return is_7bit_printable (c
);
234 if (mc_global
.full_eight_bits
)
236 return is_8bit_printable (c
);
239 return is_iso_printable (c
);
240 #endif /* !HAVE_CHARSET */
243 /* --------------------------------------------------------------------------------------------- */
245 * Quote the filename for the purpose of inserting it into the command
246 * line. If quote_percent is 1, replace "%" with "%%" - the percent is
247 * processed by the mc command line.
250 name_quote (const char *s
, int quote_percent
)
254 d
= ret
= g_malloc (strlen (s
) * 2 + 2 + 1);
306 /* --------------------------------------------------------------------------------------------- */
309 fake_name_quote (const char *s
, int quote_percent
)
311 (void) quote_percent
;
315 /* --------------------------------------------------------------------------------------------- */
317 * path_trunc() is the same as str_trunc() but
318 * it deletes possible password from path for security
323 path_trunc (const char *path
, size_t trunc_len
)
329 vpath
= vfs_path_from_str (path
);
330 secure_path
= vfs_path_to_str_flags (vpath
, 0, VPF_STRIP_PASSWORD
);
331 vfs_path_free (vpath
);
333 ret
= str_trunc (secure_path
, trunc_len
);
334 g_free (secure_path
);
339 /* --------------------------------------------------------------------------------------------- */
342 size_trunc (uintmax_t size
, gboolean use_si
)
344 static char x
[BUF_TINY
];
345 uintmax_t divisor
= 1;
346 const char *xtra
= "";
348 if (size
> 999999999UL)
350 divisor
= use_si
? 1000 : 1024;
351 xtra
= use_si
? "k" : "K";
353 if (size
/ divisor
> 999999999UL)
355 divisor
= use_si
? (1000 * 1000) : (1024 * 1024);
356 xtra
= use_si
? "m" : "M";
358 if (size
/ divisor
> 999999999UL)
360 divisor
= use_si
? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
361 xtra
= use_si
? "g" : "G";
365 g_snprintf (x
, sizeof (x
), "%.0f%s", 1.0 * size
/ divisor
, xtra
);
369 /* --------------------------------------------------------------------------------------------- */
372 size_trunc_sep (uintmax_t size
, gboolean use_si
)
379 p
= y
= size_trunc (size
, use_si
);
381 d
= x
+ sizeof (x
) - 1;
383 while (p
>= y
&& isalpha ((unsigned char) *p
))
385 for (count
= 0; p
>= y
; count
++)
400 /* --------------------------------------------------------------------------------------------- */
402 * Print file SIZE to BUFFER, but don't exceed LEN characters,
403 * not including trailing 0. BUFFER should be at least LEN+1 long.
404 * This function is called for every file on panels, so avoid
405 * floating point by any means.
407 * Units: size units (filesystem sizes are 1K blocks)
408 * 0=bytes, 1=Kbytes, 2=Mbytes, etc.
412 size_trunc_len (char *buffer
, unsigned int len
, uintmax_t size
, int units
, gboolean use_si
)
414 /* Avoid taking power for every file. */
416 static const uintmax_t power10
[] = {
417 /* we hope that size of uintmax_t is 4 bytes at least */
428 /* maximmum value of uintmax_t (in case of 4 bytes) is
431 #if SIZEOF_UINTMAX_T == 8
439 10000000000000000ULL,
440 100000000000000000ULL,
441 1000000000000000000ULL,
442 10000000000000000000ULL
443 /* maximmum value of uintmax_t (in case of 8 bytes) is
449 static const char *const suffix
[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL
};
450 static const char *const suffix_lc
[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL
};
455 #if SIZEOF_UINTMAX_T == 8
456 /* 20 decimal digits are required to represent 8 bytes */
460 /* 10 decimal digits are required to represent 4 bytes */
466 * recalculate from 1024 base to 1000 base if units>0
467 * We can't just multiply by 1024 - that might cause overflow
468 * if off_t type is too small
471 for (j
= 0; j
< units
; j
++)
473 uintmax_t size_remain
;
475 size_remain
= ((size
% 125) * 1024) / 1000; /* size mod 125, recalculated */
476 size
= size
/ 125; /* 128/125 = 1024/1000 */
477 size
= size
* 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
478 size
+= size_remain
; /* Re-add remainder lost by division/multiplication */
481 for (j
= units
; suffix
[j
] != NULL
; j
++)
487 /* Empty files will print "0" even with minimal width. */
488 g_snprintf (buffer
, len
+ 1, "0");
492 /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
493 g_snprintf (buffer
, len
+ 1, (len
> 1) ? "~%s" : "%s",
494 (j
> 1) ? (use_si
? suffix_lc
[j
- 1] : suffix
[j
- 1]) : "B");
498 if (size
< power10
[len
- (j
> 0 ? 1 : 0)])
500 g_snprintf (buffer
, len
+ 1, "%" PRIuMAX
"%s", size
, use_si
? suffix_lc
[j
] : suffix
[j
]);
504 /* Powers of 1000 or 1024, with rounding. */
506 size
= (size
+ 500) / 1000;
508 size
= (size
+ 512) >> 10;
512 /* --------------------------------------------------------------------------------------------- */
515 string_perm (mode_t mode_bits
)
517 static char mode
[11];
519 strcpy (mode
, "----------");
520 if (S_ISDIR (mode_bits
))
522 if (S_ISCHR (mode_bits
))
524 if (S_ISBLK (mode_bits
))
526 if (S_ISLNK (mode_bits
))
528 if (S_ISFIFO (mode_bits
))
530 if (S_ISNAM (mode_bits
))
532 if (S_ISSOCK (mode_bits
))
534 if (S_ISDOOR (mode_bits
))
536 if (ismode (mode_bits
, S_IXOTH
))
538 if (ismode (mode_bits
, S_IWOTH
))
540 if (ismode (mode_bits
, S_IROTH
))
542 if (ismode (mode_bits
, S_IXGRP
))
544 if (ismode (mode_bits
, S_IWGRP
))
546 if (ismode (mode_bits
, S_IRGRP
))
548 if (ismode (mode_bits
, S_IXUSR
))
550 if (ismode (mode_bits
, S_IWUSR
))
552 if (ismode (mode_bits
, S_IRUSR
))
555 if (ismode (mode_bits
, S_ISUID
))
556 mode
[3] = (mode
[3] == 'x') ? 's' : 'S';
559 if (ismode (mode_bits
, S_ISGID
))
560 mode
[6] = (mode
[6] == 'x') ? 's' : 'S';
563 if (ismode (mode_bits
, S_ISVTX
))
564 mode
[9] = (mode
[9] == 'x') ? 't' : 'T';
569 /* --------------------------------------------------------------------------------------------- */
572 extension (const char *filename
)
574 const char *d
= strrchr (filename
, '.');
575 return (d
!= NULL
) ? d
+ 1 : "";
578 /* --------------------------------------------------------------------------------------------- */
581 load_mc_home_file (const char *from
, const char *filename
, char **allocated_filename
)
583 char *hintfile_base
, *hintfile
;
587 hintfile_base
= g_build_filename (from
, filename
, (char *) NULL
);
588 lang
= guess_message_value ();
590 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
591 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
593 /* Fall back to the two-letter language code */
594 if (lang
[0] != '\0' && lang
[1] != '\0')
597 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
598 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
601 hintfile
= hintfile_base
;
602 g_file_get_contents (hintfile_base
, &data
, NULL
, NULL
);
608 if (hintfile
!= hintfile_base
)
609 g_free (hintfile_base
);
611 if (allocated_filename
!= NULL
)
612 *allocated_filename
= hintfile
;
619 /* --------------------------------------------------------------------------------------------- */
622 extract_line (const char *s
, const char *top
)
624 static char tmp_line
[BUF_MEDIUM
];
627 while (*s
&& *s
!= '\n' && (size_t) (t
- tmp_line
) < sizeof (tmp_line
) - 1 && s
< top
)
633 /* --------------------------------------------------------------------------------------------- */
635 * The basename routine
639 x_basename (const char *s
)
641 const char *url_delim
, *path_sep
;
643 url_delim
= g_strrstr (s
, VFS_PATH_URL_DELIMITER
);
644 path_sep
= strrchr (s
, PATH_SEP
);
646 if (url_delim
== NULL
647 || url_delim
< path_sep
- strlen (VFS_PATH_URL_DELIMITER
)
648 || url_delim
- s
+ strlen (VFS_PATH_URL_DELIMITER
) < strlen (s
))
650 /* avoid trailing PATH_SEP, if present */
651 if (s
[strlen (s
) - 1] == PATH_SEP
)
653 while (--path_sep
> s
&& *path_sep
!= PATH_SEP
);
654 return (path_sep
!= s
) ? path_sep
+ 1 : s
;
657 return (path_sep
!= NULL
) ? path_sep
+ 1 : s
;
660 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
661 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
663 return (url_delim
== s
) ? s
: url_delim
+ 1;
666 /* --------------------------------------------------------------------------------------------- */
669 unix_error_string (int error_num
)
671 static char buffer
[BUF_LARGE
];
672 gchar
*strerror_currentlocale
;
674 strerror_currentlocale
= g_locale_from_utf8 (g_strerror (error_num
), -1, NULL
, NULL
, NULL
);
675 g_snprintf (buffer
, sizeof (buffer
), "%s (%d)", strerror_currentlocale
, error_num
);
676 g_free (strerror_currentlocale
);
681 /* --------------------------------------------------------------------------------------------- */
684 skip_separators (const char *s
)
688 for (; *su
; str_cnext_char (&su
))
689 if (*su
!= ' ' && *su
!= '\t' && *su
!= ',')
695 /* --------------------------------------------------------------------------------------------- */
698 skip_numbers (const char *s
)
702 for (; *su
; str_cnext_char (&su
))
703 if (!str_isdigit (su
))
709 /* --------------------------------------------------------------------------------------------- */
711 * Remove all control sequences from the argument string. We define
712 * "control sequence", in a sort of pidgin BNF, as follows:
714 * control-seq = Esc non-'['
715 * | Esc '[' (0 or more digits or ';' or '?') (any other char)
717 * This scheme works for all the terminals described in my termcap /
718 * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
719 * terminals. If I hear from a single person who uses such a terminal
720 * with MC, I'll be glad to add support for it. (Dugan)
721 * Non-printable characters are also removed.
725 strip_ctrl_codes (char *s
)
727 char *w
; /* Current position where the stripped data is written */
728 char *r
; /* Current position where the original data is read */
734 for (w
= s
, r
= s
; *r
;)
738 /* Skip the control sequence's arguments */ ;
739 /* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
740 if (*(++r
) == '[' || *r
== '(')
742 /* strchr() matches trailing binary 0 */
743 while (*(++r
) && strchr ("0123456789;?", *r
));
748 * Skip xterm's OSC (Operating System Command)
749 * http://www.xfree86.org/current/ctlseqs.html
755 for (; *new_r
; ++new_r
)
765 if (*(new_r
+ 1) == '\\')
776 * Now we are at the last character of the sequence.
777 * Skip it unless it's binary 0.
784 n
= str_get_next_char (r
);
787 memmove (w
, r
, n
- r
);
796 /* --------------------------------------------------------------------------------------------- */
798 enum compression_type
799 get_compression_type (int fd
, const char *name
)
801 unsigned char magic
[16];
804 /* Read the magic signature */
805 if (mc_read (fd
, (char *) magic
, 4) != 4)
806 return COMPRESSION_NONE
;
808 /* GZIP_MAGIC and OLD_GZIP_MAGIC */
809 if (magic
[0] == 037 && (magic
[1] == 0213 || magic
[1] == 0236))
811 return COMPRESSION_GZIP
;
815 if (magic
[0] == 0120 && magic
[1] == 0113 && magic
[2] == 003 && magic
[3] == 004)
817 /* Read compression type */
818 mc_lseek (fd
, 8, SEEK_SET
);
819 if (mc_read (fd
, (char *) magic
, 2) != 2)
820 return COMPRESSION_NONE
;
822 /* Gzip can handle only deflated (8) or stored (0) files */
823 if ((magic
[0] != 8 && magic
[0] != 0) || magic
[1] != 0)
824 return COMPRESSION_NONE
;
826 /* Compatible with gzip */
827 return COMPRESSION_GZIP
;
830 /* PACK_MAGIC and LZH_MAGIC and compress magic */
831 if (magic
[0] == 037 && (magic
[1] == 036 || magic
[1] == 0240 || magic
[1] == 0235))
833 /* Compatible with gzip */
834 return COMPRESSION_GZIP
;
837 /* BZIP and BZIP2 files */
838 if ((magic
[0] == 'B') && (magic
[1] == 'Z') && (magic
[3] >= '1') && (magic
[3] <= '9'))
843 return COMPRESSION_BZIP
;
845 return COMPRESSION_BZIP2
;
849 /* Support for LZMA (only utils format with magic in header).
850 * This is the default format of LZMA utils 4.32.1 and later. */
852 if (mc_read (fd
, (char *) magic
+ 4, 2) != 2)
853 return COMPRESSION_NONE
;
855 /* LZMA utils format */
858 && magic
[2] == 'Z' && magic
[3] == 'M' && magic
[4] == 'A' && magic
[5] == 0x00)
859 return COMPRESSION_LZMA
;
861 /* XZ compression magic */
864 && magic
[2] == 0x7A && magic
[3] == 0x58 && magic
[4] == 0x5A && magic
[5] == 0x00)
865 return COMPRESSION_XZ
;
867 str_len
= strlen (name
);
868 /* HACK: we must belive to extention of LZMA file :) ... */
869 if ((str_len
> 5 && strcmp (&name
[str_len
- 5], ".lzma") == 0) ||
870 (str_len
> 4 && strcmp (&name
[str_len
- 4], ".tlz") == 0))
871 return COMPRESSION_LZMA
;
873 return COMPRESSION_NONE
;
876 /* --------------------------------------------------------------------------------------------- */
879 decompress_extension (int type
)
883 case COMPRESSION_GZIP
:
884 return "/ugz" VFS_PATH_URL_DELIMITER
;
885 case COMPRESSION_BZIP
:
886 return "/ubz" VFS_PATH_URL_DELIMITER
;
887 case COMPRESSION_BZIP2
:
888 return "/ubz2" VFS_PATH_URL_DELIMITER
;
889 case COMPRESSION_LZMA
:
890 return "/ulzma" VFS_PATH_URL_DELIMITER
;
892 return "/uxz" VFS_PATH_URL_DELIMITER
;
894 /* Should never reach this place */
895 fprintf (stderr
, "Fatal: decompress_extension called with an unknown argument\n");
899 /* --------------------------------------------------------------------------------------------- */
902 wipe_password (char *passwd
)
913 /* --------------------------------------------------------------------------------------------- */
915 * Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
917 * @param p pointer to string
919 * @return newly allocated string
923 convert_controls (const char *p
)
925 char *valcopy
= g_strdup (p
);
928 /* Parse the escape special character */
929 for (q
= valcopy
; *p
;)
934 if ((*p
== 'e') || (*p
== 'E'))
949 char c
= (*p
| 0x20);
950 if (c
>= 'a' && c
<= 'z')
967 /* --------------------------------------------------------------------------------------------- */
969 * Finds out a relative path from first to second, i.e. goes as many ..
970 * as needed up in first and then goes down using second
974 diff_two_paths (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
)
976 char *p
, *q
, *r
, *s
, *buf
= NULL
;
977 int i
, j
, prevlen
= -1, currlen
;
978 char *my_first
= NULL
, *my_second
= NULL
;
980 my_first
= resolve_symlinks (vpath1
);
981 if (my_first
== NULL
)
984 my_second
= resolve_symlinks (vpath2
);
985 if (my_second
== NULL
)
988 for (j
= 0; j
< 2; j
++)
994 r
= strchr (p
, PATH_SEP
);
995 s
= strchr (q
, PATH_SEP
);
996 if (r
== NULL
|| s
== NULL
)
1000 if (strcmp (p
, q
) != 0)
1014 for (i
= 0; (p
= strchr (p
+ 1, PATH_SEP
)) != NULL
; i
++)
1016 currlen
= (i
+ 1) * 3 + strlen (q
) + 1;
1019 if (currlen
< prevlen
)
1024 p
= buf
= g_malloc (currlen
);
1026 for (; i
>= 0; i
--, p
+= 3)
1037 /* --------------------------------------------------------------------------------------------- */
1039 * Append text to GList, remove all entries with the same text
1043 list_append_unique (GList
* list
, char *text
)
1048 * Go to the last position and traverse the list backwards
1049 * starting from the second last entry to make sure that we
1050 * are not removing the current link.
1052 list
= g_list_append (list
, text
);
1053 list
= g_list_last (list
);
1054 lc_link
= g_list_previous (list
);
1056 while (lc_link
!= NULL
)
1060 newlink
= g_list_previous (lc_link
);
1061 if (strcmp ((char *) lc_link
->data
, text
) == 0)
1065 g_free (lc_link
->data
);
1066 tmp
= g_list_remove_link (list
, lc_link
);
1068 g_list_free_1 (lc_link
);
1076 /* --------------------------------------------------------------------------------------------- */
1078 * Read and restore position for the given filename.
1079 * If there is no stored data, return line 1 and col 0.
1083 load_file_position (const vfs_path_t
* filename_vpath
, long *line
, long *column
, off_t
* offset
,
1084 GArray
** bookmarks
)
1088 char buf
[MC_MAXPATHLEN
+ 100];
1089 const size_t len
= vfs_path_len (filename_vpath
);
1097 /* open file with positions */
1098 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1099 f
= fopen (fn
, "r");
1104 /* prepare array for serialized bookmarks */
1105 *bookmarks
= g_array_sized_new (FALSE
, FALSE
, sizeof (size_t), MAX_SAVED_BOOKMARKS
);
1106 filename
= vfs_path_to_str (filename_vpath
);
1108 while (fgets (buf
, sizeof (buf
), f
) != NULL
)
1113 /* check if the filename matches the beginning of string */
1114 if (strncmp (buf
, filename
, len
) != 0)
1117 /* followed by single space */
1118 if (buf
[len
] != ' ')
1121 /* and string without spaces */
1123 if (strchr (p
, ' ') != NULL
)
1126 pos_tokens
= g_strsplit (p
, ";", 3 + MAX_SAVED_BOOKMARKS
);
1127 if (pos_tokens
[0] == NULL
)
1135 *line
= strtol (pos_tokens
[0], NULL
, 10);
1136 if (pos_tokens
[1] == NULL
)
1143 *column
= strtol (pos_tokens
[1], NULL
, 10);
1144 if (pos_tokens
[2] == NULL
)
1150 *offset
= (off_t
) g_ascii_strtoll (pos_tokens
[2], NULL
, 10);
1152 for (i
= 0; i
< MAX_SAVED_BOOKMARKS
&& pos_tokens
[3 + i
] != NULL
; i
++)
1156 val
= strtoul (pos_tokens
[3 + i
], NULL
, 10);
1157 g_array_append_val (*bookmarks
, val
);
1163 g_strfreev (pos_tokens
);
1170 /* --------------------------------------------------------------------------------------------- */
1172 * Save position for the given file
1176 save_file_position (const vfs_path_t
* filename_vpath
, long line
, long column
, off_t offset
,
1179 static size_t filepos_max_saved_entries
= 0;
1182 char buf
[MC_MAXPATHLEN
+ 100];
1184 const size_t len
= vfs_path_len (filename_vpath
);
1185 gboolean src_error
= FALSE
;
1188 if (filepos_max_saved_entries
== 0)
1189 filepos_max_saved_entries
= mc_config_get_int (mc_main_config
, CONFIG_APP_SECTION
,
1190 "filepos_max_saved_entries", 1024);
1192 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1196 mc_util_make_backup_if_possible (fn
, TMP_SUFFIX
);
1199 f
= fopen (fn
, "w");
1201 goto open_target_error
;
1203 tmp_fn
= g_strdup_printf ("%s" TMP_SUFFIX
, fn
);
1204 tmp_f
= fopen (tmp_fn
, "r");
1208 goto open_source_error
;
1211 filename
= vfs_path_to_str (filename_vpath
);
1212 /* put the new record */
1213 if (line
!= 1 || column
!= 0 || bookmarks
!= NULL
)
1215 if (fprintf (f
, "%s %ld;%ld;%" PRIuMAX
, filename
, line
, column
, (uintmax_t) offset
) < 0)
1216 goto write_position_error
;
1217 if (bookmarks
!= NULL
)
1218 for (i
= 0; i
< bookmarks
->len
&& i
< MAX_SAVED_BOOKMARKS
; i
++)
1219 if (fprintf (f
, ";%zu", g_array_index (bookmarks
, size_t, i
)) < 0)
1220 goto write_position_error
;
1222 if (fprintf (f
, "\n") < 0)
1223 goto write_position_error
;
1227 while (fgets (buf
, sizeof (buf
), tmp_f
) != NULL
)
1229 if (buf
[len
] == ' ' && strncmp (buf
, filename
, len
) == 0
1230 && strchr (&buf
[len
+ 1], ' ') == NULL
)
1233 fprintf (f
, "%s", buf
);
1234 if (++i
> filepos_max_saved_entries
)
1238 write_position_error
:
1245 mc_util_restore_from_backup_if_possible (fn
, TMP_SUFFIX
);
1247 mc_util_unlink_backup_if_possible (fn
, TMP_SUFFIX
);
1251 if (bookmarks
!= NULL
)
1252 g_array_free (bookmarks
, TRUE
);
1255 /* --------------------------------------------------------------------------------------------- */
1258 ascii_alpha_to_cntrl (int ch
)
1260 if ((ch
>= ASCII_A
&& ch
<= ASCII_Z
) || (ch
>= ASCII_a
&& ch
<= ASCII_z
))
1267 /* --------------------------------------------------------------------------------------------- */
1272 const char *result
, *sep
;
1275 sep
= strchr (result
, '|');
1276 return (sep
!= NULL
) ? sep
+ 1 : result
;
1279 /* --------------------------------------------------------------------------------------------- */
1282 mc_util_make_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1284 struct stat stat_buf
;
1287 if (!exist_file (file_name
))
1290 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1292 if (backup_path
== NULL
)
1295 ret
= mc_util_write_backup_content (file_name
, backup_path
);
1299 /* Backup file will have same ownership with main file. */
1300 if (stat (file_name
, &stat_buf
) == 0)
1301 chmod (backup_path
, stat_buf
.st_mode
);
1303 chmod (backup_path
, S_IRUSR
| S_IWUSR
);
1306 g_free (backup_path
);
1311 /* --------------------------------------------------------------------------------------------- */
1314 mc_util_restore_from_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1319 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1320 if (backup_path
== NULL
)
1323 ret
= mc_util_write_backup_content (backup_path
, file_name
);
1324 g_free (backup_path
);
1329 /* --------------------------------------------------------------------------------------------- */
1332 mc_util_unlink_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1336 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1337 if (backup_path
== NULL
)
1340 if (exist_file (backup_path
))
1344 vpath
= vfs_path_from_str (backup_path
);
1346 vfs_path_free (vpath
);
1349 g_free (backup_path
);
1353 /* --------------------------------------------------------------------------------------------- */
1355 * partly taken from dcigettext.c, returns "" for default locale
1356 * value should be freed by calling function g_free()
1360 guess_message_value (void)
1362 static const char *const var
[] = {
1363 /* Setting of LC_ALL overwrites all other. */
1364 /* Do not use LANGUAGE for check user locale and drowing hints */
1366 /* Next comes the name of the desired category. */
1368 /* Last possibility is the LANG environment variable. */
1370 /* NULL exit loops */
1375 const char *locale
= NULL
;
1377 while (var
[i
] != NULL
)
1379 locale
= getenv (var
[i
]);
1380 if (locale
!= NULL
&& locale
[0] != '\0')
1388 return g_strdup (locale
);
1391 /* --------------------------------------------------------------------------------------------- */