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 char *path
)
115 char *buf
, *buf2
, *q
, *r
, c
;
120 if (*path
!= PATH_SEP
)
122 r
= buf
= g_malloc (MC_MAXPATHLEN
);
123 buf2
= g_malloc (MC_MAXPATHLEN
);
129 q
= strchr (p
+ 1, PATH_SEP
);
132 q
= strchr (p
+ 1, 0);
138 if (mc_lstat (path
, &mybuf
) < 0)
145 if (!S_ISLNK (mybuf
.st_mode
))
149 len
= mc_readlink (path
, buf2
, MC_MAXPATHLEN
- 1);
158 if (*buf2
== PATH_SEP
)
163 canonicalize_pathname (buf
);
165 if (!*r
|| *(r
- 1) != PATH_SEP
)
176 strcpy (buf
, PATH_SEP_STR
);
177 else if (*(r
- 1) == PATH_SEP
&& r
!= buf
+ 1)
183 /* --------------------------------------------------------------------------------------------- */
186 mc_util_write_backup_content (const char *from_file_name
, const char *to_file_name
)
191 gboolean ret1
= TRUE
;
193 if (!g_file_get_contents (from_file_name
, &contents
, &length
, NULL
))
196 backup_fd
= fopen (to_file_name
, "w");
197 if (backup_fd
== NULL
)
203 if (fwrite ((const void *) contents
, 1, length
, backup_fd
) != length
)
207 ret2
= fflush (backup_fd
);
208 ret2
= fclose (backup_fd
);
214 /* --------------------------------------------------------------------------------------------- */
215 /*** public functions ****************************************************************************/
216 /* --------------------------------------------------------------------------------------------- */
224 /* "Display bits" is ignored, since the user controls the output
225 by setting the output codepage */
226 return is_8bit_printable (c
);
228 if (!mc_global
.eight_bit_clean
)
229 return is_7bit_printable (c
);
231 if (mc_global
.full_eight_bits
)
233 return is_8bit_printable (c
);
236 return is_iso_printable (c
);
237 #endif /* !HAVE_CHARSET */
240 /* --------------------------------------------------------------------------------------------- */
242 * Quote the filename for the purpose of inserting it into the command
243 * line. If quote_percent is 1, replace "%" with "%%" - the percent is
244 * processed by the mc command line.
247 name_quote (const char *s
, int quote_percent
)
251 d
= ret
= g_malloc (strlen (s
) * 2 + 2 + 1);
303 /* --------------------------------------------------------------------------------------------- */
306 fake_name_quote (const char *s
, int quote_percent
)
308 (void) quote_percent
;
312 /* --------------------------------------------------------------------------------------------- */
314 * path_trunc() is the same as str_trunc() but
315 * it deletes possible password from path for security
320 path_trunc (const char *path
, size_t trunc_len
)
322 char *secure_path
= strip_password (g_strdup (path
), 1);
324 const char *ret
= str_trunc (secure_path
, trunc_len
);
325 g_free (secure_path
);
330 /* --------------------------------------------------------------------------------------------- */
333 size_trunc (uintmax_t size
, gboolean use_si
)
335 static char x
[BUF_TINY
];
336 uintmax_t divisor
= 1;
337 const char *xtra
= "";
339 if (size
> 999999999UL)
341 divisor
= use_si
? 1000 : 1024;
342 xtra
= use_si
? "k" : "K";
344 if (size
/ divisor
> 999999999UL)
346 divisor
= use_si
? (1000 * 1000) : (1024 * 1024);
347 xtra
= use_si
? "m" : "M";
349 if (size
/ divisor
> 999999999UL)
351 divisor
= use_si
? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
352 xtra
= use_si
? "g" : "G";
356 g_snprintf (x
, sizeof (x
), "%.0f%s", 1.0 * size
/ divisor
, xtra
);
360 /* --------------------------------------------------------------------------------------------- */
363 size_trunc_sep (uintmax_t size
, gboolean use_si
)
370 p
= y
= size_trunc (size
, use_si
);
372 d
= x
+ sizeof (x
) - 1;
374 while (p
>= y
&& isalpha ((unsigned char) *p
))
376 for (count
= 0; p
>= y
; count
++)
391 /* --------------------------------------------------------------------------------------------- */
393 * Print file SIZE to BUFFER, but don't exceed LEN characters,
394 * not including trailing 0. BUFFER should be at least LEN+1 long.
395 * This function is called for every file on panels, so avoid
396 * floating point by any means.
398 * Units: size units (filesystem sizes are 1K blocks)
399 * 0=bytes, 1=Kbytes, 2=Mbytes, etc.
403 size_trunc_len (char *buffer
, unsigned int len
, uintmax_t size
, int units
, gboolean use_si
)
405 /* Avoid taking power for every file. */
407 static const uintmax_t power10
[] = {
408 /* we hope that size of uintmax_t is 4 bytes at least */
419 /* maximmum value of uintmax_t (in case of 4 bytes) is
422 #if SIZEOF_UINTMAX_T == 8
430 10000000000000000ULL,
431 100000000000000000ULL,
432 1000000000000000000ULL,
433 10000000000000000000ULL
434 /* maximmum value of uintmax_t (in case of 8 bytes) is
440 static const char *const suffix
[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL
};
441 static const char *const suffix_lc
[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL
};
446 #if SIZEOF_UINTMAX_T == 8
447 /* 20 decimal digits are required to represent 8 bytes */
451 /* 10 decimal digits are required to represent 4 bytes */
457 * recalculate from 1024 base to 1000 base if units>0
458 * We can't just multiply by 1024 - that might cause overflow
459 * if off_t type is too small
462 for (j
= 0; j
< units
; j
++)
464 uintmax_t size_remain
;
466 size_remain
= ((size
% 125) * 1024) / 1000; /* size mod 125, recalculated */
467 size
= size
/ 125; /* 128/125 = 1024/1000 */
468 size
= size
* 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
469 size
+= size_remain
; /* Re-add remainder lost by division/multiplication */
472 for (j
= units
; suffix
[j
] != NULL
; j
++)
478 /* Empty files will print "0" even with minimal width. */
479 g_snprintf (buffer
, len
+ 1, "0");
483 /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
484 g_snprintf (buffer
, len
+ 1, (len
> 1) ? "~%s" : "%s",
485 (j
> 1) ? (use_si
? suffix_lc
[j
- 1] : suffix
[j
- 1]) : "B");
489 if (size
< power10
[len
- (j
> 0 ? 1 : 0)])
491 g_snprintf (buffer
, len
+ 1, "%" PRIuMAX
"%s", size
, use_si
? suffix_lc
[j
] : suffix
[j
]);
495 /* Powers of 1000 or 1024, with rounding. */
497 size
= (size
+ 500) / 1000;
499 size
= (size
+ 512) >> 10;
503 /* --------------------------------------------------------------------------------------------- */
506 string_perm (mode_t mode_bits
)
508 static char mode
[11];
510 strcpy (mode
, "----------");
511 if (S_ISDIR (mode_bits
))
513 if (S_ISCHR (mode_bits
))
515 if (S_ISBLK (mode_bits
))
517 if (S_ISLNK (mode_bits
))
519 if (S_ISFIFO (mode_bits
))
521 if (S_ISNAM (mode_bits
))
523 if (S_ISSOCK (mode_bits
))
525 if (S_ISDOOR (mode_bits
))
527 if (ismode (mode_bits
, S_IXOTH
))
529 if (ismode (mode_bits
, S_IWOTH
))
531 if (ismode (mode_bits
, S_IROTH
))
533 if (ismode (mode_bits
, S_IXGRP
))
535 if (ismode (mode_bits
, S_IWGRP
))
537 if (ismode (mode_bits
, S_IRGRP
))
539 if (ismode (mode_bits
, S_IXUSR
))
541 if (ismode (mode_bits
, S_IWUSR
))
543 if (ismode (mode_bits
, S_IRUSR
))
546 if (ismode (mode_bits
, S_ISUID
))
547 mode
[3] = (mode
[3] == 'x') ? 's' : 'S';
550 if (ismode (mode_bits
, S_ISGID
))
551 mode
[6] = (mode
[6] == 'x') ? 's' : 'S';
554 if (ismode (mode_bits
, S_ISVTX
))
555 mode
[9] = (mode
[9] == 'x') ? 't' : 'T';
560 /* --------------------------------------------------------------------------------------------- */
562 * p: string which might contain an url with a password (this parameter is
563 * modified in place).
564 * has_prefix = 0: The first parameter is an url without a prefix
565 * (user[:pass]@]machine[:port][remote-dir). Delete
567 * has_prefix = 1: Search p for known url prefixes. If found delete
568 * the password from the url.
569 * Caveat: only the first url is found
573 strip_password (char *p
, int has_prefix
)
592 char *at
, *inner_colon
, *dir
;
596 for (i
= 0; i
< sizeof (prefixes
) / sizeof (prefixes
[0]); i
++)
602 q
= strstr (p
, prefixes
[i
].name
);
606 p
= q
+ prefixes
[i
].len
;
609 dir
= strchr (p
, PATH_SEP
);
613 /* search for any possible user */
614 at
= strrchr (p
, '@');
619 /* We have a username */
622 inner_colon
= memchr (p
, ':', at
- p
);
624 memmove (inner_colon
, at
, strlen (at
) + 1);
631 /* --------------------------------------------------------------------------------------------- */
634 strip_home_and_password (const char *dir
)
637 static char newdir
[MC_MAXPATHLEN
];
639 len
= strlen (mc_config_get_home_dir ());
640 if (mc_config_get_home_dir () != NULL
&& strncmp (dir
, mc_config_get_home_dir (), len
) == 0 &&
641 (dir
[len
] == PATH_SEP
|| dir
[len
] == '\0'))
644 g_strlcpy (&newdir
[1], &dir
[len
], sizeof (newdir
) - 1);
648 /* We do not strip homes in /#ftp tree, I do not like ~'s there
650 g_strlcpy (newdir
, dir
, sizeof (newdir
));
651 strip_password (newdir
, 1);
655 /* --------------------------------------------------------------------------------------------- */
658 extension (const char *filename
)
660 const char *d
= strrchr (filename
, '.');
661 return (d
!= NULL
) ? d
+ 1 : "";
664 /* --------------------------------------------------------------------------------------------- */
667 load_mc_home_file (const char *from
, const char *filename
, char **allocated_filename
)
669 char *hintfile_base
, *hintfile
;
673 hintfile_base
= g_build_filename (from
, filename
, (char *) NULL
);
674 lang
= guess_message_value ();
676 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
677 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
679 /* Fall back to the two-letter language code */
680 if (lang
[0] != '\0' && lang
[1] != '\0')
683 hintfile
= g_strconcat (hintfile_base
, ".", lang
, (char *) NULL
);
684 if (!g_file_get_contents (hintfile
, &data
, NULL
, NULL
))
687 hintfile
= hintfile_base
;
688 g_file_get_contents (hintfile_base
, &data
, NULL
, NULL
);
694 if (hintfile
!= hintfile_base
)
695 g_free (hintfile_base
);
697 if (allocated_filename
!= NULL
)
698 *allocated_filename
= hintfile
;
705 /* --------------------------------------------------------------------------------------------- */
708 extract_line (const char *s
, const char *top
)
710 static char tmp_line
[BUF_MEDIUM
];
713 while (*s
&& *s
!= '\n' && (size_t) (t
- tmp_line
) < sizeof (tmp_line
) - 1 && s
< top
)
719 /* --------------------------------------------------------------------------------------------- */
721 * The basename routine
725 x_basename (const char *s
)
727 const char *url_delim
, *path_sep
;
729 url_delim
= g_strrstr (s
, VFS_PATH_URL_DELIMITER
);
730 path_sep
= strrchr (s
, PATH_SEP
);
732 if (url_delim
== NULL
733 || url_delim
< path_sep
- strlen (VFS_PATH_URL_DELIMITER
)
734 || url_delim
- s
+ strlen (VFS_PATH_URL_DELIMITER
) < strlen (s
))
736 /* avoid trailing PATH_SEP, if present */
737 if (s
[strlen (s
) - 1] == PATH_SEP
)
739 while (--path_sep
> s
&& *path_sep
!= PATH_SEP
);
740 return (path_sep
!= s
) ? path_sep
+ 1 : s
;
743 return (path_sep
!= NULL
) ? path_sep
+ 1 : s
;
746 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
747 while (--url_delim
> s
&& *url_delim
!= PATH_SEP
);
749 return (url_delim
== s
) ? s
: url_delim
+ 1;
752 /* --------------------------------------------------------------------------------------------- */
755 unix_error_string (int error_num
)
757 static char buffer
[BUF_LARGE
];
758 gchar
*strerror_currentlocale
;
760 strerror_currentlocale
= g_locale_from_utf8 (g_strerror (error_num
), -1, NULL
, NULL
, NULL
);
761 g_snprintf (buffer
, sizeof (buffer
), "%s (%d)", strerror_currentlocale
, error_num
);
762 g_free (strerror_currentlocale
);
767 /* --------------------------------------------------------------------------------------------- */
770 skip_separators (const char *s
)
774 for (; *su
; str_cnext_char (&su
))
775 if (*su
!= ' ' && *su
!= '\t' && *su
!= ',')
781 /* --------------------------------------------------------------------------------------------- */
784 skip_numbers (const char *s
)
788 for (; *su
; str_cnext_char (&su
))
789 if (!str_isdigit (su
))
795 /* --------------------------------------------------------------------------------------------- */
797 * Remove all control sequences from the argument string. We define
798 * "control sequence", in a sort of pidgin BNF, as follows:
800 * control-seq = Esc non-'['
801 * | Esc '[' (0 or more digits or ';' or '?') (any other char)
803 * This scheme works for all the terminals described in my termcap /
804 * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
805 * terminals. If I hear from a single person who uses such a terminal
806 * with MC, I'll be glad to add support for it. (Dugan)
807 * Non-printable characters are also removed.
811 strip_ctrl_codes (char *s
)
813 char *w
; /* Current position where the stripped data is written */
814 char *r
; /* Current position where the original data is read */
820 for (w
= s
, r
= s
; *r
;)
824 /* Skip the control sequence's arguments */ ;
825 /* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
826 if (*(++r
) == '[' || *r
== '(')
828 /* strchr() matches trailing binary 0 */
829 while (*(++r
) && strchr ("0123456789;?", *r
));
834 * Skip xterm's OSC (Operating System Command)
835 * http://www.xfree86.org/current/ctlseqs.html
841 for (; *new_r
; ++new_r
)
851 if (*(new_r
+ 1) == '\\')
862 * Now we are at the last character of the sequence.
863 * Skip it unless it's binary 0.
870 n
= str_get_next_char (r
);
873 memmove (w
, r
, n
- r
);
882 /* --------------------------------------------------------------------------------------------- */
884 enum compression_type
885 get_compression_type (int fd
, const char *name
)
887 unsigned char magic
[16];
890 /* Read the magic signature */
891 if (mc_read (fd
, (char *) magic
, 4) != 4)
892 return COMPRESSION_NONE
;
894 /* GZIP_MAGIC and OLD_GZIP_MAGIC */
895 if (magic
[0] == 037 && (magic
[1] == 0213 || magic
[1] == 0236))
897 return COMPRESSION_GZIP
;
901 if (magic
[0] == 0120 && magic
[1] == 0113 && magic
[2] == 003 && magic
[3] == 004)
903 /* Read compression type */
904 mc_lseek (fd
, 8, SEEK_SET
);
905 if (mc_read (fd
, (char *) magic
, 2) != 2)
906 return COMPRESSION_NONE
;
908 /* Gzip can handle only deflated (8) or stored (0) files */
909 if ((magic
[0] != 8 && magic
[0] != 0) || magic
[1] != 0)
910 return COMPRESSION_NONE
;
912 /* Compatible with gzip */
913 return COMPRESSION_GZIP
;
916 /* PACK_MAGIC and LZH_MAGIC and compress magic */
917 if (magic
[0] == 037 && (magic
[1] == 036 || magic
[1] == 0240 || magic
[1] == 0235))
919 /* Compatible with gzip */
920 return COMPRESSION_GZIP
;
923 /* BZIP and BZIP2 files */
924 if ((magic
[0] == 'B') && (magic
[1] == 'Z') && (magic
[3] >= '1') && (magic
[3] <= '9'))
929 return COMPRESSION_BZIP
;
931 return COMPRESSION_BZIP2
;
935 /* Support for LZMA (only utils format with magic in header).
936 * This is the default format of LZMA utils 4.32.1 and later. */
938 if (mc_read (fd
, (char *) magic
+ 4, 2) != 2)
939 return COMPRESSION_NONE
;
941 /* LZMA utils format */
944 && magic
[2] == 'Z' && magic
[3] == 'M' && magic
[4] == 'A' && magic
[5] == 0x00)
945 return COMPRESSION_LZMA
;
947 /* XZ compression magic */
950 && magic
[2] == 0x7A && magic
[3] == 0x58 && magic
[4] == 0x5A && magic
[5] == 0x00)
951 return COMPRESSION_XZ
;
953 str_len
= strlen (name
);
954 /* HACK: we must belive to extention of LZMA file :) ... */
955 if ((str_len
> 5 && strcmp (&name
[str_len
- 5], ".lzma") == 0) ||
956 (str_len
> 4 && strcmp (&name
[str_len
- 4], ".tlz") == 0))
957 return COMPRESSION_LZMA
;
959 return COMPRESSION_NONE
;
962 /* --------------------------------------------------------------------------------------------- */
965 decompress_extension (int type
)
969 case COMPRESSION_GZIP
:
970 return "/ugz" VFS_PATH_URL_DELIMITER
;
971 case COMPRESSION_BZIP
:
972 return "/ubz" VFS_PATH_URL_DELIMITER
;
973 case COMPRESSION_BZIP2
:
974 return "/ubz2" VFS_PATH_URL_DELIMITER
;
975 case COMPRESSION_LZMA
:
976 return "/ulzma" VFS_PATH_URL_DELIMITER
;
978 return "/uxz" VFS_PATH_URL_DELIMITER
;
980 /* Should never reach this place */
981 fprintf (stderr
, "Fatal: decompress_extension called with an unknown argument\n");
985 /* --------------------------------------------------------------------------------------------- */
988 wipe_password (char *passwd
)
999 /* --------------------------------------------------------------------------------------------- */
1001 * Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
1002 * @returns a newly allocated string
1006 convert_controls (const char *p
)
1008 char *valcopy
= g_strdup (p
);
1011 /* Parse the escape special character */
1012 for (q
= valcopy
; *p
;)
1017 if ((*p
== 'e') || (*p
== 'E'))
1032 char c
= (*p
| 0x20);
1033 if (c
>= 'a' && c
<= 'z')
1050 /* --------------------------------------------------------------------------------------------- */
1052 * Finds out a relative path from first to second, i.e. goes as many ..
1053 * as needed up in first and then goes down using second
1057 diff_two_paths (const char *first
, const char *second
)
1059 char *p
, *q
, *r
, *s
, *buf
= NULL
;
1060 int i
, j
, prevlen
= -1, currlen
;
1061 char *my_first
= NULL
, *my_second
= NULL
;
1063 my_first
= resolve_symlinks (first
);
1064 if (my_first
== NULL
)
1066 my_second
= resolve_symlinks (second
);
1067 if (my_second
== NULL
)
1072 for (j
= 0; j
< 2; j
++)
1078 r
= strchr (p
, PATH_SEP
);
1079 s
= strchr (q
, PATH_SEP
);
1099 for (i
= 0; (p
= strchr (p
+ 1, PATH_SEP
)) != NULL
; i
++);
1100 currlen
= (i
+ 1) * 3 + strlen (q
) + 1;
1103 if (currlen
< prevlen
)
1112 p
= buf
= g_malloc (currlen
);
1114 for (; i
>= 0; i
--, p
+= 3)
1123 /* --------------------------------------------------------------------------------------------- */
1125 * If filename is NULL, then we just append PATH_SEP to the dir
1129 concat_dir_and_file (const char *dir
, const char *file
)
1131 int i
= strlen (dir
);
1133 if (dir
[i
- 1] == PATH_SEP
)
1134 return g_strconcat (dir
, file
, (char *) NULL
);
1136 return g_strconcat (dir
, PATH_SEP_STR
, file
, (char *) NULL
);
1139 /* --------------------------------------------------------------------------------------------- */
1141 * Append text to GList, remove all entries with the same text
1145 list_append_unique (GList
* list
, char *text
)
1150 * Go to the last position and traverse the list backwards
1151 * starting from the second last entry to make sure that we
1152 * are not removing the current link.
1154 list
= g_list_append (list
, text
);
1155 list
= g_list_last (list
);
1156 lc_link
= g_list_previous (list
);
1158 while (lc_link
!= NULL
)
1162 newlink
= g_list_previous (lc_link
);
1163 if (strcmp ((char *) lc_link
->data
, text
) == 0)
1167 g_free (lc_link
->data
);
1168 tmp
= g_list_remove_link (list
, lc_link
);
1169 g_list_free_1 (lc_link
);
1177 /* --------------------------------------------------------------------------------------------- */
1178 /* Following code heavily borrows from libiberty, mkstemps.c */
1181 * pname (output) - pointer to the name of the temp file (needs g_free).
1182 * NULL if the function fails.
1183 * prefix - part of the filename before the random part.
1184 * Prepend $TMPDIR or /tmp if there are no path separators.
1185 * suffix - if not NULL, part of the filename after the random part.
1188 * handle of the open file or -1 if couldn't open any.
1192 mc_mkstemps (char **pname
, const char *prefix
, const char *suffix
)
1194 static const char letters
[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1195 static unsigned long value
;
1202 if (strchr (prefix
, PATH_SEP
) == NULL
)
1204 /* Add prefix first to find the position of XXXXXX */
1205 tmpbase
= concat_dir_and_file (mc_tmpdir (), prefix
);
1209 tmpbase
= g_strdup (prefix
);
1212 tmpname
= g_strconcat (tmpbase
, "XXXXXX", suffix
, (char *) NULL
);
1214 XXXXXX
= &tmpname
[strlen (tmpbase
)];
1217 /* Get some more or less random data. */
1218 gettimeofday (&tv
, NULL
);
1219 value
+= (tv
.tv_usec
<< 16) ^ tv
.tv_sec
^ getpid ();
1221 for (count
= 0; count
< TMP_MAX
; ++count
)
1223 unsigned long v
= value
;
1226 /* Fill in the random bits. */
1227 XXXXXX
[0] = letters
[v
% 62];
1229 XXXXXX
[1] = letters
[v
% 62];
1231 XXXXXX
[2] = letters
[v
% 62];
1233 XXXXXX
[3] = letters
[v
% 62];
1235 XXXXXX
[4] = letters
[v
% 62];
1237 XXXXXX
[5] = letters
[v
% 62];
1239 fd
= open (tmpname
, O_RDWR
| O_CREAT
| O_TRUNC
| O_EXCL
, S_IRUSR
| S_IWUSR
);
1242 /* Successfully created. */
1246 /* This is a random value. It is only necessary that the next
1247 TMP_MAX values generated by adding 7777 to VALUE are different
1248 with (module 2^32). */
1252 /* Unsuccessful. Free the filename. */
1259 /* --------------------------------------------------------------------------------------------- */
1261 * Read and restore position for the given filename.
1262 * If there is no stored data, return line 1 and col 0.
1266 load_file_position (const char *filename
, long *line
, long *column
, off_t
* offset
,
1267 GArray
** bookmarks
)
1271 char buf
[MC_MAXPATHLEN
+ 100];
1272 const size_t len
= strlen (filename
);
1279 /* open file with positions */
1280 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1281 f
= fopen (fn
, "r");
1286 /* prepare array for serialized bookmarks */
1287 *bookmarks
= g_array_sized_new (FALSE
, FALSE
, sizeof (size_t), MAX_SAVED_BOOKMARKS
);
1289 while (fgets (buf
, sizeof (buf
), f
) != NULL
)
1294 /* check if the filename matches the beginning of string */
1295 if (strncmp (buf
, filename
, len
) != 0)
1298 /* followed by single space */
1299 if (buf
[len
] != ' ')
1302 /* and string without spaces */
1304 if (strchr (p
, ' ') != NULL
)
1307 pos_tokens
= g_strsplit (p
, ";", 3 + MAX_SAVED_BOOKMARKS
);
1308 if (pos_tokens
[0] == NULL
)
1316 *line
= strtol (pos_tokens
[0], NULL
, 10);
1317 if (pos_tokens
[1] == NULL
)
1324 *column
= strtol (pos_tokens
[1], NULL
, 10);
1325 if (pos_tokens
[2] == NULL
)
1331 *offset
= strtoll (pos_tokens
[2], NULL
, 10);
1333 for (i
= 0; i
< MAX_SAVED_BOOKMARKS
&& pos_tokens
[3 + i
] != NULL
; i
++)
1337 val
= strtoul (pos_tokens
[3 + i
], NULL
, 10);
1338 g_array_append_val (*bookmarks
, val
);
1344 g_strfreev (pos_tokens
);
1350 /* --------------------------------------------------------------------------------------------- */
1352 * Save position for the given file
1356 save_file_position (const char *filename
, long line
, long column
, off_t offset
, GArray
* bookmarks
)
1358 static size_t filepos_max_saved_entries
= 0;
1361 char buf
[MC_MAXPATHLEN
+ 100];
1363 const size_t len
= strlen (filename
);
1364 gboolean src_error
= FALSE
;
1366 if (filepos_max_saved_entries
== 0)
1367 filepos_max_saved_entries
= mc_config_get_int (mc_main_config
, CONFIG_APP_SECTION
,
1368 "filepos_max_saved_entries", 1024);
1370 fn
= mc_config_get_full_path (MC_FILEPOS_FILE
);
1374 mc_util_make_backup_if_possible (fn
, TMP_SUFFIX
);
1377 f
= fopen (fn
, "w");
1379 goto open_target_error
;
1381 tmp_fn
= g_strdup_printf ("%s" TMP_SUFFIX
, fn
);
1382 tmp_f
= fopen (tmp_fn
, "r");
1386 goto open_source_error
;
1389 /* put the new record */
1390 if (line
!= 1 || column
!= 0 || bookmarks
!= NULL
)
1392 if (fprintf (f
, "%s %ld;%ld;%" PRIuMAX
, filename
, line
, column
, (uintmax_t) offset
) < 0)
1393 goto write_position_error
;
1394 if (bookmarks
!= NULL
)
1395 for (i
= 0; i
< bookmarks
->len
&& i
< MAX_SAVED_BOOKMARKS
; i
++)
1396 if (fprintf (f
, ";%zu", g_array_index (bookmarks
, size_t, i
)) < 0)
1397 goto write_position_error
;
1399 if (fprintf (f
, "\n") < 0)
1400 goto write_position_error
;
1404 while (fgets (buf
, sizeof (buf
), tmp_f
) != NULL
)
1406 if (buf
[len
] == ' ' && strncmp (buf
, filename
, len
) == 0
1407 && strchr (&buf
[len
+ 1], ' ') == NULL
)
1410 fprintf (f
, "%s", buf
);
1411 if (++i
> filepos_max_saved_entries
)
1415 write_position_error
:
1421 mc_util_restore_from_backup_if_possible (fn
, TMP_SUFFIX
);
1423 mc_util_unlink_backup_if_possible (fn
, TMP_SUFFIX
);
1427 if (bookmarks
!= NULL
)
1428 g_array_free (bookmarks
, TRUE
);
1431 /* --------------------------------------------------------------------------------------------- */
1434 ascii_alpha_to_cntrl (int ch
)
1436 if ((ch
>= ASCII_A
&& ch
<= ASCII_Z
) || (ch
>= ASCII_a
&& ch
<= ASCII_z
))
1443 /* --------------------------------------------------------------------------------------------- */
1448 const char *result
, *sep
;
1451 sep
= strchr (result
, '|');
1452 return (sep
!= NULL
) ? sep
+ 1 : result
;
1455 /* --------------------------------------------------------------------------------------------- */
1458 mc_util_make_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1460 struct stat stat_buf
;
1463 if (!exist_file (file_name
))
1466 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1468 if (backup_path
== NULL
)
1471 ret
= mc_util_write_backup_content (file_name
, backup_path
);
1475 /* Backup file will have same ownership with main file. */
1476 if (stat (file_name
, &stat_buf
) == 0)
1477 chmod (backup_path
, stat_buf
.st_mode
);
1479 chmod (backup_path
, S_IRUSR
| S_IWUSR
);
1482 g_free (backup_path
);
1487 /* --------------------------------------------------------------------------------------------- */
1490 mc_util_restore_from_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1495 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1496 if (backup_path
== NULL
)
1499 ret
= mc_util_write_backup_content (backup_path
, file_name
);
1500 g_free (backup_path
);
1505 /* --------------------------------------------------------------------------------------------- */
1508 mc_util_unlink_backup_if_possible (const char *file_name
, const char *backup_suffix
)
1512 backup_path
= g_strdup_printf ("%s%s", file_name
, backup_suffix
);
1513 if (backup_path
== NULL
)
1516 if (exist_file (backup_path
))
1517 mc_unlink (backup_path
);
1519 g_free (backup_path
);
1523 /* --------------------------------------------------------------------------------------------- */
1525 * partly taken from dcigettext.c, returns "" for default locale
1526 * value should be freed by calling function g_free()
1530 guess_message_value (void)
1532 static const char *const var
[] = {
1533 /* Setting of LC_ALL overwrites all other. */
1534 /* Do not use LANGUAGE for check user locale and drowing hints */
1536 /* Next comes the name of the desired category. */
1538 /* Last possibility is the LANG environment variable. */
1540 /* NULL exit loops */
1545 const char *locale
= NULL
;
1547 while (var
[i
] != NULL
)
1549 locale
= getenv (var
[i
]);
1550 if (locale
!= NULL
&& locale
[0] != '\0')
1558 return g_strdup (locale
);
1561 /* --------------------------------------------------------------------------------------------- */