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 The file_date routine is mostly from GNU's fileutils package,
16 written by Richard Stallman and David MacKenzie.
18 This file is part of the Midnight Commander.
20 The Midnight Commander is free software: you can redistribute it
21 and/or modify it under the terms of the GNU General Public License as
22 published by the Free Software Foundation, either version 3 of the License,
23 or (at your option) any later version.
25 The Midnight Commander is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
30 You should have received a copy of the GNU General Public License
31 along with this program. If not, see <http://www.gnu.org/licenses/>.
35 * \brief Source: various utilities
48 #include <sys/types.h>
52 #include "lib/global.h"
53 #include "lib/mcconfig.h"
54 #include "lib/fileloc.h"
55 #include "lib/vfs/vfs.h"
56 #include "lib/strutil.h"
59 /*** global variables ****************************************************************************/
61 /*** file scope macro definitions ****************************************************************/
63 #define ismode(n,m) ((n & m) == m)
65 /* Number of attempts to create a temporary file */
70 #define TMP_SUFFIX ".tmp"
72 #define ASCII_A (0x40 + 1)
73 #define ASCII_Z (0x40 + 26)
74 #define ASCII_a (0x60 + 1)
75 #define ASCII_z (0x60 + 26)
77 /*** file scope type declarations ****************************************************************/
79 /*** file scope variables ************************************************************************/
81 /*** file scope functions ************************************************************************/
82 /* --------------------------------------------------------------------------------------------- */
85 is_7bit_printable (unsigned char c
)
87 return (c
> 31 && c
< 127);
90 /* --------------------------------------------------------------------------------------------- */
93 is_iso_printable (unsigned char c
)
95 return ((c
> 31 && c
< 127) || c
>= 160);
98 /* --------------------------------------------------------------------------------------------- */
101 is_8bit_printable (unsigned char c
)
103 /* "Full 8 bits output" doesn't work on xterm */
104 if (mc_global
.tty
.xterm_flag
)
105 return is_iso_printable (c
);
107 return (c
> 31 && c
!= 127 && c
!= 155);
110 /* --------------------------------------------------------------------------------------------- */
113 resolve_symlinks (const vfs_path_t
* vpath
)
116 char *buf
, *buf2
, *q
, *r
, c
;
122 p
= p2
= vfs_path_to_str (vpath
);
123 r
= buf
= g_malloc (MC_MAXPATHLEN
);
124 buf2
= g_malloc (MC_MAXPATHLEN
);
130 q
= strchr (p
+ 1, PATH_SEP
);
133 q
= strchr (p
+ 1, 0);
139 if (mc_lstat (vpath
, &mybuf
) < 0)
145 if (!S_ISLNK (mybuf
.st_mode
))
151 len
= mc_readlink (vpath
, buf2
, MC_MAXPATHLEN
- 1);
159 if (*buf2
== PATH_SEP
)
164 canonicalize_pathname (buf
);
166 if (!*r
|| *(r
- 1) != PATH_SEP
)
167 /* FIXME: this condition is always true because r points to the EOL */
178 strcpy (buf
, PATH_SEP_STR
);
179 else if (*(r
- 1) == PATH_SEP
&& r
!= buf
+ 1)
188 /* --------------------------------------------------------------------------------------------- */
191 mc_util_write_backup_content (const char *from_file_name
, const char *to_file_name
)
196 gboolean ret1
= TRUE
;
198 if (!g_file_get_contents (from_file_name
, &contents
, &length
, NULL
))
201 backup_fd
= fopen (to_file_name
, "w");
202 if (backup_fd
== NULL
)
208 if (fwrite ((const void *) contents
, 1, length
, backup_fd
) != length
)
212 ret2
= fflush (backup_fd
);
213 ret2
= fclose (backup_fd
);
219 /* --------------------------------------------------------------------------------------------- */
220 /*** public functions ****************************************************************************/
221 /* --------------------------------------------------------------------------------------------- */
229 /* "Display bits" is ignored, since the user controls the output
230 by setting the output codepage */
231 return is_8bit_printable (c
);
233 if (!mc_global
.eight_bit_clean
)
234 return is_7bit_printable (c
);
236 if (mc_global
.full_eight_bits
)
238 return is_8bit_printable (c
);
241 return is_iso_printable (c
);
242 #endif /* !HAVE_CHARSET */
245 /* --------------------------------------------------------------------------------------------- */
247 * Quote the filename for the purpose of inserting it into the command
248 * line. If quote_percent is 1, replace "%" with "%%" - the percent is
249 * processed by the mc command line.
252 name_quote (const char *s
, int quote_percent
)
256 d
= ret
= g_malloc (strlen (s
) * 2 + 2 + 1);
308 /* --------------------------------------------------------------------------------------------- */
311 fake_name_quote (const char *s
, int quote_percent
)
313 (void) quote_percent
;
317 /* --------------------------------------------------------------------------------------------- */
319 * path_trunc() is the same as str_trunc() but
320 * it deletes possible password from path for security
325 path_trunc (const char *path
, size_t trunc_len
)
331 vpath
= vfs_path_from_str (path
);
332 secure_path
= vfs_path_to_str_flags (vpath
, 0, VPF_STRIP_PASSWORD
);
333 vfs_path_free (vpath
);
335 ret
= str_trunc (secure_path
, trunc_len
);
336 g_free (secure_path
);
341 /* --------------------------------------------------------------------------------------------- */
344 size_trunc (uintmax_t size
, gboolean use_si
)
346 static char x
[BUF_TINY
];
347 uintmax_t divisor
= 1;
348 const char *xtra
= "";
350 if (size
> 999999999UL)
352 divisor
= use_si
? 1000 : 1024;
353 xtra
= use_si
? "k" : "K";
355 if (size
/ divisor
> 999999999UL)
357 divisor
= use_si
? (1000 * 1000) : (1024 * 1024);
358 xtra
= use_si
? "m" : "M";
360 if (size
/ divisor
> 999999999UL)
362 divisor
= use_si
? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
363 xtra
= use_si
? "g" : "G";
367 g_snprintf (x
, sizeof (x
), "%.0f%s", 1.0 * size
/ divisor
, xtra
);
371 /* --------------------------------------------------------------------------------------------- */
374 size_trunc_sep (uintmax_t size
, gboolean use_si
)
381 p
= y
= size_trunc (size
, use_si
);
383 d
= x
+ sizeof (x
) - 1;
385 while (p
>= y
&& isalpha ((unsigned char) *p
))
387 for (count
= 0; p
>= y
; count
++)
402 /* --------------------------------------------------------------------------------------------- */
404 * Print file SIZE to BUFFER, but don't exceed LEN characters,
405 * not including trailing 0. BUFFER should be at least LEN+1 long.
406 * This function is called for every file on panels, so avoid
407 * floating point by any means.
409 * Units: size units (filesystem sizes are 1K blocks)
410 * 0=bytes, 1=Kbytes, 2=Mbytes, etc.
414 size_trunc_len (char *buffer
, unsigned int len
, uintmax_t size
, int units
, gboolean use_si
)
416 /* Avoid taking power for every file. */
418 static const uintmax_t power10
[] = {
419 /* we hope that size of uintmax_t is 4 bytes at least */
430 /* maximmum value of uintmax_t (in case of 4 bytes) is
433 #if SIZEOF_UINTMAX_T == 8
441 10000000000000000ULL,
442 100000000000000000ULL,
443 1000000000000000000ULL,
444 10000000000000000000ULL
445 /* maximmum value of uintmax_t (in case of 8 bytes) is
451 static const char *const suffix
[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL
};
452 static const char *const suffix_lc
[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL
};
457 #if SIZEOF_UINTMAX_T == 8
458 /* 20 decimal digits are required to represent 8 bytes */
462 /* 10 decimal digits are required to represent 4 bytes */
468 * recalculate from 1024 base to 1000 base if units>0
469 * We can't just multiply by 1024 - that might cause overflow
470 * if off_t type is too small
473 for (j
= 0; j
< units
; j
++)
475 uintmax_t size_remain
;
477 size_remain
= ((size
% 125) * 1024) / 1000; /* size mod 125, recalculated */
478 size
= size
/ 125; /* 128/125 = 1024/1000 */
479 size
= size
* 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
480 size
+= size_remain
; /* Re-add remainder lost by division/multiplication */
483 for (j
= units
; suffix
[j
] != NULL
; j
++)
489 /* Empty files will print "0" even with minimal width. */
490 g_snprintf (buffer
, len
+ 1, "0");
494 /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
495 g_snprintf (buffer
, len
+ 1, (len
> 1) ? "~%s" : "%s",
496 (j
> 1) ? (use_si
? suffix_lc
[j
- 1] : suffix
[j
- 1]) : "B");
500 if (size
< power10
[len
- (j
> 0 ? 1 : 0)])
502 g_snprintf (buffer
, len
+ 1, "%" PRIuMAX
"%s", size
, use_si
? suffix_lc
[j
] : suffix
[j
]);
506 /* Powers of 1000 or 1024, with rounding. */
508 size
= (size
+ 500) / 1000;
510 size
= (size
+ 512) >> 10;
514 /* --------------------------------------------------------------------------------------------- */
517 string_perm (mode_t mode_bits
)
519 static char mode
[11];
521 strcpy (mode
, "----------");
522 if (S_ISDIR (mode_bits
))
524 if (S_ISCHR (mode_bits
))
526 if (S_ISBLK (mode_bits
))
528 if (S_ISLNK (mode_bits
))
530 if (S_ISFIFO (mode_bits
))
532 if (S_ISNAM (mode_bits
))
534 if (S_ISSOCK (mode_bits
))
536 if (S_ISDOOR (mode_bits
))
538 if (ismode (mode_bits
, S_IXOTH
))
540 if (ismode (mode_bits
, S_IWOTH
))
542 if (ismode (mode_bits
, S_IROTH
))
544 if (ismode (mode_bits
, S_IXGRP
))
546 if (ismode (mode_bits
, S_IWGRP
))
548 if (ismode (mode_bits
, S_IRGRP
))
550 if (ismode (mode_bits
, S_IXUSR
))
552 if (ismode (mode_bits
, S_IWUSR
))
554 if (ismode (mode_bits
, S_IRUSR
))
557 if (ismode (mode_bits
, S_ISUID
))
558 mode
[3] = (mode
[3] == 'x') ? 's' : 'S';
561 if (ismode (mode_bits
, S_ISGID
))
562 mode
[6] = (mode
[6] == 'x') ? 's' : 'S';
565 if (ismode (mode_bits
, S_ISVTX
))
566 mode
[9] = (mode
[9] == 'x') ? 't' : 'T';
571 /* --------------------------------------------------------------------------------------------- */
574 extension (const char *filename
)
576 const char *d
= strrchr (filename
, '.');
577 return (d
!= NULL
) ? d
+ 1 : "";
580 /* --------------------------------------------------------------------------------------------- */
583 load_mc_home_file (const char *from
, const char *filename
, char **allocated_filename
)
585 char *hintfile_base
, *hintfile
;
589 hintfile_base
= g_build_filename (from
, filename
, (char *) NULL
);
590 lang
= guess_message_value ();
592 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
593 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
595 /* Fall back to the two-letter language code */
596 if (lang
[0] != '\0' && lang
[1] != '\0')
599 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
600 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
603 hintfile
= hintfile_base
;
604 g_file_get_contents (hintfile_base
, &data
, NULL
, NULL
);
610 if (hintfile
!= hintfile_base
)
611 g_free (hintfile_base
);
613 if (allocated_filename
!= NULL
)
614 *allocated_filename
= hintfile
;
621 /* --------------------------------------------------------------------------------------------- */
624 extract_line (const char *s
, const char *top
)
626 static char tmp_line
[BUF_MEDIUM
];
629 while (*s
&& *s
!= '\n' && (size_t) (t
- tmp_line
) < sizeof (tmp_line
) - 1 && s
< top
)
635 /* --------------------------------------------------------------------------------------------- */
637 * The basename routine
641 x_basename (const char *s
)
643 const char *url_delim
, *path_sep
;
645 url_delim
= g_strrstr (s
, VFS_PATH_URL_DELIMITER
);
646 path_sep
= strrchr (s
, PATH_SEP
);
648 if (url_delim
== NULL
649 || url_delim
< path_sep
- strlen (VFS_PATH_URL_DELIMITER
)
650 || url_delim
- s
+ strlen (VFS_PATH_URL_DELIMITER
) < strlen (s
))
652 /* avoid trailing PATH_SEP, if present */
653 if (s
[strlen (s
) - 1] == PATH_SEP
)
655 while (--path_sep
> s
&& *path_sep
!= PATH_SEP
);
656 return (path_sep
!= s
) ? path_sep
+ 1 : s
;
659 return (path_sep
!= NULL
) ? path_sep
+ 1 : s
;
662 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
663 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
665 return (url_delim
== s
) ? s
: url_delim
+ 1;
668 /* --------------------------------------------------------------------------------------------- */
671 unix_error_string (int error_num
)
673 static char buffer
[BUF_LARGE
];
674 gchar
*strerror_currentlocale
;
676 strerror_currentlocale
= g_locale_from_utf8 (g_strerror (error_num
), -1, NULL
, NULL
, NULL
);
677 g_snprintf (buffer
, sizeof (buffer
), "%s (%d)", strerror_currentlocale
, error_num
);
678 g_free (strerror_currentlocale
);
683 /* --------------------------------------------------------------------------------------------- */
686 skip_separators (const char *s
)
690 for (; *su
; str_cnext_char (&su
))
691 if (*su
!= ' ' && *su
!= '\t' && *su
!= ',')
697 /* --------------------------------------------------------------------------------------------- */
700 skip_numbers (const char *s
)
704 for (; *su
; str_cnext_char (&su
))
705 if (!str_isdigit (su
))
711 /* --------------------------------------------------------------------------------------------- */
713 * Remove all control sequences from the argument string. We define
714 * "control sequence", in a sort of pidgin BNF, as follows:
716 * control-seq = Esc non-'['
717 * | Esc '[' (0 or more digits or ';' or '?') (any other char)
719 * This scheme works for all the terminals described in my termcap /
720 * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
721 * terminals. If I hear from a single person who uses such a terminal
722 * with MC, I'll be glad to add support for it. (Dugan)
723 * Non-printable characters are also removed.
727 strip_ctrl_codes (char *s
)
729 char *w
; /* Current position where the stripped data is written */
730 char *r
; /* Current position where the original data is read */
736 for (w
= s
, r
= s
; *r
;)
740 /* Skip the control sequence's arguments */ ;
741 /* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
742 if (*(++r
) == '[' || *r
== '(')
744 /* strchr() matches trailing binary 0 */
745 while (*(++r
) && strchr ("0123456789;?", *r
));
750 * Skip xterm's OSC (Operating System Command)
751 * http://www.xfree86.org/current/ctlseqs.html
757 for (; *new_r
; ++new_r
)
767 if (*(new_r
+ 1) == '\\')
778 * Now we are at the last character of the sequence.
779 * Skip it unless it's binary 0.
786 n
= str_get_next_char (r
);
789 memmove (w
, r
, n
- r
);
798 /* --------------------------------------------------------------------------------------------- */
800 enum compression_type
801 get_compression_type (int fd
, const char *name
)
803 unsigned char magic
[16];
806 /* Read the magic signature */
807 if (mc_read (fd
, (char *) magic
, 4) != 4)
808 return COMPRESSION_NONE
;
810 /* GZIP_MAGIC and OLD_GZIP_MAGIC */
811 if (magic
[0] == 037 && (magic
[1] == 0213 || magic
[1] == 0236))
813 return COMPRESSION_GZIP
;
817 if (magic
[0] == 0120 && magic
[1] == 0113 && magic
[2] == 003 && magic
[3] == 004)
819 /* Read compression type */
820 mc_lseek (fd
, 8, SEEK_SET
);
821 if (mc_read (fd
, (char *) magic
, 2) != 2)
822 return COMPRESSION_NONE
;
824 /* Gzip can handle only deflated (8) or stored (0) files */
825 if ((magic
[0] != 8 && magic
[0] != 0) || magic
[1] != 0)
826 return COMPRESSION_NONE
;
828 /* Compatible with gzip */
829 return COMPRESSION_GZIP
;
832 /* PACK_MAGIC and LZH_MAGIC and compress magic */
833 if (magic
[0] == 037 && (magic
[1] == 036 || magic
[1] == 0240 || magic
[1] == 0235))
835 /* Compatible with gzip */
836 return COMPRESSION_GZIP
;
839 /* BZIP and BZIP2 files */
840 if ((magic
[0] == 'B') && (magic
[1] == 'Z') && (magic
[3] >= '1') && (magic
[3] <= '9'))
845 return COMPRESSION_BZIP
;
847 return COMPRESSION_BZIP2
;
851 /* Support for LZMA (only utils format with magic in header).
852 * This is the default format of LZMA utils 4.32.1 and later. */
854 if (mc_read (fd
, (char *) magic
+ 4, 2) != 2)
855 return COMPRESSION_NONE
;
857 /* LZMA utils format */
860 && magic
[2] == 'Z' && magic
[3] == 'M' && magic
[4] == 'A' && magic
[5] == 0x00)
861 return COMPRESSION_LZMA
;
863 /* XZ compression magic */
866 && magic
[2] == 0x7A && magic
[3] == 0x58 && magic
[4] == 0x5A && magic
[5] == 0x00)
867 return COMPRESSION_XZ
;
869 str_len
= strlen (name
);
870 /* HACK: we must belive to extention of LZMA file :) ... */
871 if ((str_len
> 5 && strcmp (&name
[str_len
- 5], ".lzma") == 0) ||
872 (str_len
> 4 && strcmp (&name
[str_len
- 4], ".tlz") == 0))
873 return COMPRESSION_LZMA
;
875 return COMPRESSION_NONE
;
878 /* --------------------------------------------------------------------------------------------- */
881 decompress_extension (int type
)
885 case COMPRESSION_GZIP
:
886 return "/ugz" VFS_PATH_URL_DELIMITER
;
887 case COMPRESSION_BZIP
:
888 return "/ubz" VFS_PATH_URL_DELIMITER
;
889 case COMPRESSION_BZIP2
:
890 return "/ubz2" VFS_PATH_URL_DELIMITER
;
891 case COMPRESSION_LZMA
:
892 return "/ulzma" VFS_PATH_URL_DELIMITER
;
894 return "/uxz" VFS_PATH_URL_DELIMITER
;
896 /* Should never reach this place */
897 fprintf (stderr
, "Fatal: decompress_extension called with an unknown argument\n");
901 /* --------------------------------------------------------------------------------------------- */
904 wipe_password (char *passwd
)
915 /* --------------------------------------------------------------------------------------------- */
917 * Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
918 * @returns a newly allocated string
922 convert_controls (const char *p
)
924 char *valcopy
= g_strdup (p
);
927 /* Parse the escape special character */
928 for (q
= valcopy
; *p
;)
933 if ((*p
== 'e') || (*p
== 'E'))
948 char c
= (*p
| 0x20);
949 if (c
>= 'a' && c
<= 'z')
966 /* --------------------------------------------------------------------------------------------- */
968 * Finds out a relative path from first to second, i.e. goes as many ..
969 * as needed up in first and then goes down using second
973 diff_two_paths (const vfs_path_t
* vpath1
, const vfs_path_t
* vpath2
)
975 char *p
, *q
, *r
, *s
, *buf
= NULL
;
976 int i
, j
, prevlen
= -1, currlen
;
977 char *my_first
= NULL
, *my_second
= NULL
;
979 my_first
= resolve_symlinks (vpath1
);
980 if (my_first
== NULL
)
983 my_second
= resolve_symlinks (vpath2
);
984 if (my_second
== NULL
)
987 for (j
= 0; j
< 2; j
++)
993 r
= strchr (p
, PATH_SEP
);
994 s
= strchr (q
, PATH_SEP
);
1014 for (i
= 0; (p
= strchr (p
+ 1, PATH_SEP
)) != NULL
; i
++);
1015 currlen
= (i
+ 1) * 3 + strlen (q
) + 1;
1018 if (currlen
< prevlen
)
1023 p
= buf
= g_malloc (currlen
);
1025 for (; i
>= 0; i
--, p
+= 3)
1036 /* --------------------------------------------------------------------------------------------- */
1038 * Append text to GList, remove all entries with the same text
1042 list_append_unique (GList
* list
, char *text
)
1047 * Go to the last position and traverse the list backwards
1048 * starting from the second last entry to make sure that we
1049 * are not removing the current link.
1051 list
= g_list_append (list
, text
);
1052 list
= g_list_last (list
);
1053 lc_link
= g_list_previous (list
);
1055 while (lc_link
!= NULL
)
1059 newlink
= g_list_previous (lc_link
);
1060 if (strcmp ((char *) lc_link
->data
, text
) == 0)
1064 g_free (lc_link
->data
);
1065 tmp
= g_list_remove_link (list
, lc_link
);
1066 g_list_free_1 (lc_link
);
1074 /* --------------------------------------------------------------------------------------------- */
1076 * Read and restore position for the given filename.
1077 * If there is no stored data, return line 1 and col 0.
1081 load_file_position (const vfs_path_t
* filename_vpath
, long *line
, long *column
, off_t
* offset
,
1082 GArray
** bookmarks
)
1086 char buf
[MC_MAXPATHLEN
+ 100];
1087 const size_t len
= vfs_path_len (filename_vpath
);
1095 /* open file with positions */
1096 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1097 f
= fopen (fn
, "r");
1102 /* prepare array for serialized bookmarks */
1103 *bookmarks
= g_array_sized_new (FALSE
, FALSE
, sizeof (size_t), MAX_SAVED_BOOKMARKS
);
1104 filename
= vfs_path_to_str (filename_vpath
);
1106 while (fgets (buf
, sizeof (buf
), f
) != NULL
)
1111 /* check if the filename matches the beginning of string */
1112 if (strncmp (buf
, filename
, len
) != 0)
1115 /* followed by single space */
1116 if (buf
[len
] != ' ')
1119 /* and string without spaces */
1121 if (strchr (p
, ' ') != NULL
)
1124 pos_tokens
= g_strsplit (p
, ";", 3 + MAX_SAVED_BOOKMARKS
);
1125 if (pos_tokens
[0] == NULL
)
1133 *line
= strtol (pos_tokens
[0], NULL
, 10);
1134 if (pos_tokens
[1] == NULL
)
1141 *column
= strtol (pos_tokens
[1], NULL
, 10);
1142 if (pos_tokens
[2] == NULL
)
1148 *offset
= strtoll (pos_tokens
[2], NULL
, 10);
1150 for (i
= 0; i
< MAX_SAVED_BOOKMARKS
&& pos_tokens
[3 + i
] != NULL
; i
++)
1154 val
= strtoul (pos_tokens
[3 + i
], NULL
, 10);
1155 g_array_append_val (*bookmarks
, val
);
1161 g_strfreev (pos_tokens
);
1168 /* --------------------------------------------------------------------------------------------- */
1170 * Save position for the given file
1174 save_file_position (const vfs_path_t
* filename_vpath
, long line
, long column
, off_t offset
,
1177 static size_t filepos_max_saved_entries
= 0;
1180 char buf
[MC_MAXPATHLEN
+ 100];
1182 const size_t len
= vfs_path_len (filename_vpath
);
1183 gboolean src_error
= FALSE
;
1186 if (filepos_max_saved_entries
== 0)
1187 filepos_max_saved_entries
= mc_config_get_int (mc_main_config
, CONFIG_APP_SECTION
,
1188 "filepos_max_saved_entries", 1024);
1190 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1194 mc_util_make_backup_if_possible (fn
, TMP_SUFFIX
);
1197 f
= fopen (fn
, "w");
1199 goto open_target_error
;
1201 tmp_fn
= g_strdup_printf ("%s" TMP_SUFFIX
, fn
);
1202 tmp_f
= fopen (tmp_fn
, "r");
1206 goto open_source_error
;
1209 filename
= vfs_path_to_str (filename_vpath
);
1210 /* put the new record */
1211 if (line
!= 1 || column
!= 0 || bookmarks
!= NULL
)
1213 if (fprintf (f
, "%s %ld;%ld;%" PRIuMAX
, filename
, line
, column
, (uintmax_t) offset
) < 0)
1214 goto write_position_error
;
1215 if (bookmarks
!= NULL
)
1216 for (i
= 0; i
< bookmarks
->len
&& i
< MAX_SAVED_BOOKMARKS
; i
++)
1217 if (fprintf (f
, ";%zu", g_array_index (bookmarks
, size_t, i
)) < 0)
1218 goto write_position_error
;
1220 if (fprintf (f
, "\n") < 0)
1221 goto write_position_error
;
1225 while (fgets (buf
, sizeof (buf
), tmp_f
) != NULL
)
1227 if (buf
[len
] == ' ' && strncmp (buf
, filename
, len
) == 0
1228 && strchr (&buf
[len
+ 1], ' ') == NULL
)
1231 fprintf (f
, "%s", buf
);
1232 if (++i
> filepos_max_saved_entries
)
1236 write_position_error
:
1243 mc_util_restore_from_backup_if_possible (fn
, TMP_SUFFIX
);
1245 mc_util_unlink_backup_if_possible (fn
, TMP_SUFFIX
);
1249 if (bookmarks
!= NULL
)
1250 g_array_free (bookmarks
, TRUE
);
1253 /* --------------------------------------------------------------------------------------------- */
1256 ascii_alpha_to_cntrl (int ch
)
1258 if ((ch
>= ASCII_A
&& ch
<= ASCII_Z
) || (ch
>= ASCII_a
&& ch
<= ASCII_z
))
1265 /* --------------------------------------------------------------------------------------------- */
1270 const char *result
, *sep
;
1273 sep
= strchr (result
, '|');
1274 return (sep
!= NULL
) ? sep
+ 1 : result
;
1277 /* --------------------------------------------------------------------------------------------- */
1280 mc_util_make_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1282 struct stat stat_buf
;
1285 if (!exist_file (file_name
))
1288 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1290 if (backup_path
== NULL
)
1293 ret
= mc_util_write_backup_content (file_name
, backup_path
);
1297 /* Backup file will have same ownership with main file. */
1298 if (stat (file_name
, &stat_buf
) == 0)
1299 chmod (backup_path
, stat_buf
.st_mode
);
1301 chmod (backup_path
, S_IRUSR
| S_IWUSR
);
1304 g_free (backup_path
);
1309 /* --------------------------------------------------------------------------------------------- */
1312 mc_util_restore_from_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1317 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1318 if (backup_path
== NULL
)
1321 ret
= mc_util_write_backup_content (backup_path
, file_name
);
1322 g_free (backup_path
);
1327 /* --------------------------------------------------------------------------------------------- */
1330 mc_util_unlink_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1334 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1335 if (backup_path
== NULL
)
1338 if (exist_file (backup_path
))
1342 vpath
= vfs_path_from_str (backup_path
);
1344 vfs_path_free (vpath
);
1347 g_free (backup_path
);
1351 /* --------------------------------------------------------------------------------------------- */
1353 * partly taken from dcigettext.c, returns "" for default locale
1354 * value should be freed by calling function g_free()
1358 guess_message_value (void)
1360 static const char *const var
[] = {
1361 /* Setting of LC_ALL overwrites all other. */
1362 /* Do not use LANGUAGE for check user locale and drowing hints */
1364 /* Next comes the name of the desired category. */
1366 /* Last possibility is the LANG environment variable. */
1368 /* NULL exit loops */
1373 const char *locale
= NULL
;
1375 while (var
[i
] != NULL
)
1377 locale
= getenv (var
[i
]);
1378 if (locale
!= NULL
&& locale
[0] != '\0')
1386 return g_strdup (locale
);
1389 /* --------------------------------------------------------------------------------------------- */