Fix use of uninitialized memory in sigaction structure.
[midnight-commander.git] / lib / util.c
bloba34d1b8616784c369cf573dc175b8957ff35a5d3
1 /*
2 Various utilities
4 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
5 2004, 2005, 2007, 2009, 2011, 2013
6 The Free Software Foundation, Inc.
8 Written by:
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
14 Slava Zanko <slavazanko@gmail.com>, 2013
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 /** \file lib/util.c
33 * \brief Source: various utilities
36 #include <config.h>
38 #include <ctype.h>
39 #include <limits.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <fcntl.h>
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
50 #include "lib/global.h"
51 #include "lib/mcconfig.h"
52 #include "lib/fileloc.h"
53 #include "lib/vfs/vfs.h"
54 #include "lib/strutil.h"
55 #include "lib/util.h"
57 /*** global variables ****************************************************************************/
59 /*** file scope macro definitions ****************************************************************/
61 #define ismode(n,m) ((n & m) == m)
63 /* Number of attempts to create a temporary file */
64 #ifndef TMP_MAX
65 #define TMP_MAX 16384
66 #endif /* !TMP_MAX */
68 #define TMP_SUFFIX ".tmp"
70 #define ASCII_A (0x40 + 1)
71 #define ASCII_Z (0x40 + 26)
72 #define ASCII_a (0x60 + 1)
73 #define ASCII_z (0x60 + 26)
75 /*** file scope type declarations ****************************************************************/
77 /*** file scope variables ************************************************************************/
79 /*** file scope functions ************************************************************************/
80 /* --------------------------------------------------------------------------------------------- */
82 static inline int
83 is_7bit_printable (unsigned char c)
85 return (c > 31 && c < 127);
88 /* --------------------------------------------------------------------------------------------- */
90 static inline int
91 is_iso_printable (unsigned char c)
93 return ((c > 31 && c < 127) || c >= 160);
96 /* --------------------------------------------------------------------------------------------- */
98 static inline int
99 is_8bit_printable (unsigned char c)
101 /* "Full 8 bits output" doesn't work on xterm */
102 if (mc_global.tty.xterm_flag)
103 return is_iso_printable (c);
105 return (c > 31 && c != 127 && c != 155);
108 /* --------------------------------------------------------------------------------------------- */
110 static char *
111 resolve_symlinks (const vfs_path_t * vpath)
113 char *p, *p2;
114 char *buf, *buf2, *q, *r, c;
115 struct stat mybuf;
117 if (vpath->relative)
118 return NULL;
120 p = p2 = g_strdup (vfs_path_as_str (vpath));
121 r = buf = g_malloc (MC_MAXPATHLEN);
122 buf2 = g_malloc (MC_MAXPATHLEN);
123 *r++ = PATH_SEP;
124 *r = 0;
128 q = strchr (p + 1, PATH_SEP);
129 if (!q)
131 q = strchr (p + 1, 0);
132 if (q == p + 1)
133 break;
135 c = *q;
136 *q = 0;
137 if (mc_lstat (vpath, &mybuf) < 0)
139 g_free (buf);
140 buf = NULL;
141 goto ret;
143 if (!S_ISLNK (mybuf.st_mode))
144 strcpy (r, p + 1);
145 else
147 int len;
149 len = mc_readlink (vpath, buf2, MC_MAXPATHLEN - 1);
150 if (len < 0)
152 g_free (buf);
153 buf = NULL;
154 goto ret;
156 buf2[len] = 0;
157 if (*buf2 == PATH_SEP)
158 strcpy (buf, buf2);
159 else
160 strcpy (r, buf2);
162 canonicalize_pathname (buf);
163 r = strchr (buf, 0);
164 if (!*r || *(r - 1) != PATH_SEP)
165 /* FIXME: this condition is always true because r points to the EOL */
167 *r++ = PATH_SEP;
168 *r = 0;
170 *q = c;
171 p = q;
173 while (c != '\0');
175 if (!*buf)
176 strcpy (buf, PATH_SEP_STR);
177 else if (*(r - 1) == PATH_SEP && r != buf + 1)
178 *(r - 1) = 0;
180 ret:
181 g_free (buf2);
182 g_free (p2);
183 return buf;
186 /* --------------------------------------------------------------------------------------------- */
188 static gboolean
189 mc_util_write_backup_content (const char *from_file_name, const char *to_file_name)
191 FILE *backup_fd;
192 char *contents;
193 gsize length;
194 gboolean ret1 = TRUE;
196 if (!g_file_get_contents (from_file_name, &contents, &length, NULL))
197 return FALSE;
199 backup_fd = fopen (to_file_name, "w");
200 if (backup_fd == NULL)
202 g_free (contents);
203 return FALSE;
206 if (fwrite ((const void *) contents, 1, length, backup_fd) != length)
207 ret1 = FALSE;
209 int ret2;
211 /* cppcheck-suppress redundantAssignment */
212 ret2 = fflush (backup_fd);
213 /* cppcheck-suppress redundantAssignment */
214 ret2 = fclose (backup_fd);
215 (void) ret2;
217 g_free (contents);
218 return ret1;
221 /* --------------------------------------------------------------------------------------------- */
222 /*** public functions ****************************************************************************/
223 /* --------------------------------------------------------------------------------------------- */
226 is_printable (int c)
228 c &= 0xff;
230 #ifdef HAVE_CHARSET
231 /* "Display bits" is ignored, since the user controls the output
232 by setting the output codepage */
233 return is_8bit_printable (c);
234 #else
235 if (!mc_global.eight_bit_clean)
236 return is_7bit_printable (c);
238 if (mc_global.full_eight_bits)
240 return is_8bit_printable (c);
242 else
243 return is_iso_printable (c);
244 #endif /* !HAVE_CHARSET */
247 /* --------------------------------------------------------------------------------------------- */
249 * Quote the filename for the purpose of inserting it into the command
250 * line. If quote_percent is 1, replace "%" with "%%" - the percent is
251 * processed by the mc command line.
253 char *
254 name_quote (const char *s, int quote_percent)
256 char *ret, *d;
258 d = ret = g_malloc (strlen (s) * 2 + 2 + 1);
259 if (*s == '-')
261 *d++ = '.';
262 *d++ = '/';
265 for (; *s; s++, d++)
267 switch (*s)
269 case '%':
270 if (quote_percent)
271 *d++ = '%';
272 break;
273 case '\'':
274 case '\\':
275 case '\r':
276 case '\n':
277 case '\t':
278 case '"':
279 case ';':
280 case ' ':
281 case '?':
282 case '|':
283 case '[':
284 case ']':
285 case '{':
286 case '}':
287 case '<':
288 case '>':
289 case '`':
290 case '!':
291 case '$':
292 case '&':
293 case '*':
294 case '(':
295 case ')':
296 *d++ = '\\';
297 break;
298 case '~':
299 case '#':
300 if (d == ret)
301 *d++ = '\\';
302 break;
304 *d = *s;
306 *d = '\0';
307 return ret;
310 /* --------------------------------------------------------------------------------------------- */
312 char *
313 fake_name_quote (const char *s, int quote_percent)
315 (void) quote_percent;
316 return g_strdup (s);
319 /* --------------------------------------------------------------------------------------------- */
321 * path_trunc() is the same as str_trunc() but
322 * it deletes possible password from path for security
323 * reasons.
326 const char *
327 path_trunc (const char *path, size_t trunc_len)
329 vfs_path_t *vpath;
330 char *secure_path;
331 const char *ret;
333 vpath = vfs_path_from_str (path);
334 secure_path = vfs_path_to_str_flags (vpath, 0, VPF_STRIP_PASSWORD);
335 vfs_path_free (vpath);
337 ret = str_trunc (secure_path, trunc_len);
338 g_free (secure_path);
340 return ret;
343 /* --------------------------------------------------------------------------------------------- */
345 const char *
346 size_trunc (uintmax_t size, gboolean use_si)
348 static char x[BUF_TINY];
349 uintmax_t divisor = 1;
350 const char *xtra = "";
352 if (size > 999999999UL)
354 divisor = use_si ? 1000 : 1024;
355 xtra = use_si ? "k" : "K";
357 if (size / divisor > 999999999UL)
359 divisor = use_si ? (1000 * 1000) : (1024 * 1024);
360 xtra = use_si ? "m" : "M";
362 if (size / divisor > 999999999UL)
364 divisor = use_si ? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
365 xtra = use_si ? "g" : "G";
369 g_snprintf (x, sizeof (x), "%.0f%s", 1.0 * size / divisor, xtra);
370 return x;
373 /* --------------------------------------------------------------------------------------------- */
375 const char *
376 size_trunc_sep (uintmax_t size, gboolean use_si)
378 static char x[60];
379 int count;
380 const char *p, *y;
381 char *d;
383 p = y = size_trunc (size, use_si);
384 p += strlen (p) - 1;
385 d = x + sizeof (x) - 1;
386 *d-- = '\0';
387 while (p >= y && isalpha ((unsigned char) *p))
388 *d-- = *p--;
389 for (count = 0; p >= y; count++)
391 if (count == 3)
393 *d-- = ',';
394 count = 0;
396 *d-- = *p--;
398 d++;
399 if (*d == ',')
400 d++;
401 return d;
404 /* --------------------------------------------------------------------------------------------- */
406 * Print file SIZE to BUFFER, but don't exceed LEN characters,
407 * not including trailing 0. BUFFER should be at least LEN+1 long.
408 * This function is called for every file on panels, so avoid
409 * floating point by any means.
411 * Units: size units (filesystem sizes are 1K blocks)
412 * 0=bytes, 1=Kbytes, 2=Mbytes, etc.
415 void
416 size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gboolean use_si)
418 /* Avoid taking power for every file. */
419 /* *INDENT-OFF* */
420 static const uintmax_t power10[] = {
421 /* we hope that size of uintmax_t is 4 bytes at least */
422 1ULL,
423 10ULL,
424 100ULL,
425 1000ULL,
426 10000ULL,
427 100000ULL,
428 1000000ULL,
429 10000000ULL,
430 100000000ULL,
431 1000000000ULL
432 /* maximum value of uintmax_t (in case of 4 bytes) is
433 4294967295
435 #if SIZEOF_UINTMAX_T == 8
437 10000000000ULL,
438 100000000000ULL,
439 1000000000000ULL,
440 10000000000000ULL,
441 100000000000000ULL,
442 1000000000000000ULL,
443 10000000000000000ULL,
444 100000000000000000ULL,
445 1000000000000000000ULL,
446 10000000000000000000ULL
447 /* maximum value of uintmax_t (in case of 8 bytes) is
448 18447644073710439615
450 #endif
452 /* *INDENT-ON* */
453 static const char *const suffix[] = { "", "K", "M", "G", "T", "P", "E", "Z", "Y", NULL };
454 static const char *const suffix_lc[] = { "", "k", "m", "g", "t", "p", "e", "z", "y", NULL };
456 const char *const *sfx = use_si ? suffix_lc : suffix;
457 int j = 0;
459 if (len == 0)
460 len = 9;
461 #if SIZEOF_UINTMAX_T == 8
462 /* 20 decimal digits are required to represent 8 bytes */
463 else if (len > 19)
464 len = 19;
465 #else
466 /* 10 decimal digits are required to represent 4 bytes */
467 else if (len > 9)
468 len = 9;
469 #endif
472 * recalculate from 1024 base to 1000 base if units>0
473 * We can't just multiply by 1024 - that might cause overflow
474 * if uintmax_t type is too small
476 if (use_si)
477 for (j = 0; j < units; j++)
479 uintmax_t size_remain;
481 size_remain = ((size % 125) * 1024) / 1000; /* size mod 125, recalculated */
482 size /= 125; /* 128/125 = 1024/1000 */
483 size *= 128; /* This will convert size from multiple of 1024 to multiple of 1000 */
484 size += size_remain; /* Re-add remainder lost by division/multiplication */
487 for (j = units; sfx[j] != NULL; j++)
489 if (size == 0)
491 if (j == units)
493 /* Empty files will print "0" even with minimal width. */
494 g_snprintf (buffer, len + 1, "%s", "0");
496 else
498 /* Use "~K" or just "K" if len is 1. Use "B" for bytes. */
499 g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", (j > 1) ? sfx[j - 1] : "B");
501 break;
504 if (size < power10[len - (j > 0 ? 1 : 0)])
506 g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, sfx[j]);
507 break;
510 /* Powers of 1000 or 1024, with rounding. */
511 if (use_si)
512 size = (size + 500) / 1000;
513 else
514 size = (size + 512) >> 10;
518 /* --------------------------------------------------------------------------------------------- */
520 const char *
521 string_perm (mode_t mode_bits)
523 static char mode[11];
525 strcpy (mode, "----------");
526 if (S_ISDIR (mode_bits))
527 mode[0] = 'd';
528 if (S_ISCHR (mode_bits))
529 mode[0] = 'c';
530 if (S_ISBLK (mode_bits))
531 mode[0] = 'b';
532 if (S_ISLNK (mode_bits))
533 mode[0] = 'l';
534 if (S_ISFIFO (mode_bits))
535 mode[0] = 'p';
536 if (S_ISNAM (mode_bits))
537 mode[0] = 'n';
538 if (S_ISSOCK (mode_bits))
539 mode[0] = 's';
540 if (S_ISDOOR (mode_bits))
541 mode[0] = 'D';
542 if (ismode (mode_bits, S_IXOTH))
543 mode[9] = 'x';
544 if (ismode (mode_bits, S_IWOTH))
545 mode[8] = 'w';
546 if (ismode (mode_bits, S_IROTH))
547 mode[7] = 'r';
548 if (ismode (mode_bits, S_IXGRP))
549 mode[6] = 'x';
550 if (ismode (mode_bits, S_IWGRP))
551 mode[5] = 'w';
552 if (ismode (mode_bits, S_IRGRP))
553 mode[4] = 'r';
554 if (ismode (mode_bits, S_IXUSR))
555 mode[3] = 'x';
556 if (ismode (mode_bits, S_IWUSR))
557 mode[2] = 'w';
558 if (ismode (mode_bits, S_IRUSR))
559 mode[1] = 'r';
560 #ifdef S_ISUID
561 if (ismode (mode_bits, S_ISUID))
562 mode[3] = (mode[3] == 'x') ? 's' : 'S';
563 #endif /* S_ISUID */
564 #ifdef S_ISGID
565 if (ismode (mode_bits, S_ISGID))
566 mode[6] = (mode[6] == 'x') ? 's' : 'S';
567 #endif /* S_ISGID */
568 #ifdef S_ISVTX
569 if (ismode (mode_bits, S_ISVTX))
570 mode[9] = (mode[9] == 'x') ? 't' : 'T';
571 #endif /* S_ISVTX */
572 return mode;
575 /* --------------------------------------------------------------------------------------------- */
577 const char *
578 extension (const char *filename)
580 const char *d = strrchr (filename, '.');
581 return (d != NULL) ? d + 1 : "";
584 /* --------------------------------------------------------------------------------------------- */
586 char *
587 load_mc_home_file (const char *from, const char *filename, char **allocated_filename)
589 char *hintfile_base, *hintfile;
590 char *lang;
591 char *data;
593 hintfile_base = g_build_filename (from, filename, (char *) NULL);
594 lang = guess_message_value ();
596 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
597 if (!g_file_get_contents (hintfile, &data, NULL, NULL))
599 /* Fall back to the two-letter language code */
600 if (lang[0] != '\0' && lang[1] != '\0')
601 lang[2] = '\0';
602 g_free (hintfile);
603 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
604 if (!g_file_get_contents (hintfile, &data, NULL, NULL))
606 g_free (hintfile);
607 hintfile = hintfile_base;
608 g_file_get_contents (hintfile_base, &data, NULL, NULL);
612 g_free (lang);
614 if (hintfile != hintfile_base)
615 g_free (hintfile_base);
617 if (allocated_filename != NULL)
618 *allocated_filename = hintfile;
619 else
620 g_free (hintfile);
622 return data;
625 /* --------------------------------------------------------------------------------------------- */
627 const char *
628 extract_line (const char *s, const char *top)
630 static char tmp_line[BUF_MEDIUM];
631 char *t = tmp_line;
633 while (*s && *s != '\n' && (size_t) (t - tmp_line) < sizeof (tmp_line) - 1 && s < top)
634 *t++ = *s++;
635 *t = 0;
636 return tmp_line;
639 /* --------------------------------------------------------------------------------------------- */
641 * The basename routine
644 const char *
645 x_basename (const char *s)
647 const char *url_delim, *path_sep;
649 url_delim = g_strrstr (s, VFS_PATH_URL_DELIMITER);
650 path_sep = strrchr (s, PATH_SEP);
652 if (url_delim == NULL
653 || url_delim < path_sep - strlen (VFS_PATH_URL_DELIMITER)
654 || url_delim - s + strlen (VFS_PATH_URL_DELIMITER) < strlen (s))
656 /* avoid trailing PATH_SEP, if present */
657 if (s[strlen (s) - 1] == PATH_SEP)
659 while (--path_sep > s && *path_sep != PATH_SEP);
660 return (path_sep != s) ? path_sep + 1 : s;
662 else
663 return (path_sep != NULL) ? path_sep + 1 : s;
666 while (--url_delim > s && *url_delim != PATH_SEP);
667 while (--url_delim > s && *url_delim != PATH_SEP);
669 return (url_delim == s) ? s : url_delim + 1;
672 /* --------------------------------------------------------------------------------------------- */
674 const char *
675 unix_error_string (int error_num)
677 static char buffer[BUF_LARGE];
678 gchar *strerror_currentlocale;
680 strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
681 g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
682 g_free (strerror_currentlocale);
684 return buffer;
687 /* --------------------------------------------------------------------------------------------- */
689 const char *
690 skip_separators (const char *s)
692 const char *su = s;
694 for (; *su; str_cnext_char (&su))
695 if (*su != ' ' && *su != '\t' && *su != ',')
696 break;
698 return su;
701 /* --------------------------------------------------------------------------------------------- */
703 const char *
704 skip_numbers (const char *s)
706 const char *su = s;
708 for (; *su; str_cnext_char (&su))
709 if (!str_isdigit (su))
710 break;
712 return su;
715 /* --------------------------------------------------------------------------------------------- */
717 * Remove all control sequences from the argument string. We define
718 * "control sequence", in a sort of pidgin BNF, as follows:
720 * control-seq = Esc non-'['
721 * | Esc '[' (0 or more digits or ';' or '?') (any other char)
723 * This scheme works for all the terminals described in my termcap /
724 * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
725 * terminals. If I hear from a single person who uses such a terminal
726 * with MC, I'll be glad to add support for it. (Dugan)
727 * Non-printable characters are also removed.
730 char *
731 strip_ctrl_codes (char *s)
733 char *w; /* Current position where the stripped data is written */
734 char *r; /* Current position where the original data is read */
736 if (s == NULL)
737 return NULL;
739 for (w = s, r = s; *r != '\0';)
741 if (*r == ESC_CHAR)
743 /* Skip the control sequence's arguments */ ;
744 /* '(' need to avoid strange 'B' letter in *Suse (if mc runs under root user) */
745 if (*(++r) == '[' || *r == '(')
747 /* strchr() matches trailing binary 0 */
748 while (*(++r) != '\0' && strchr ("0123456789;?", *r) != NULL)
751 else if (*r == ']')
754 * Skip xterm's OSC (Operating System Command)
755 * http://www.xfree86.org/current/ctlseqs.html
756 * OSC P s ; P t ST
757 * OSC P s ; P t BEL
759 char *new_r = r;
761 for (; *new_r != '\0'; ++new_r)
763 switch (*new_r)
765 /* BEL */
766 case '\a':
767 r = new_r;
768 goto osc_out;
769 case ESC_CHAR:
770 /* ST */
771 if (*(new_r + 1) == '\\')
773 r = new_r + 1;
774 goto osc_out;
778 osc_out:
783 * Now we are at the last character of the sequence.
784 * Skip it unless it's binary 0.
786 if (*r != '\0')
787 r++;
789 else
791 char *n;
793 n = str_get_next_char (r);
794 if (str_isprint (r))
796 memmove (w, r, n - r);
797 w += n - r;
799 r = n;
803 *w = '\0';
804 return s;
807 /* --------------------------------------------------------------------------------------------- */
809 enum compression_type
810 get_compression_type (int fd, const char *name)
812 unsigned char magic[16];
813 size_t str_len;
815 /* Read the magic signature */
816 if (mc_read (fd, (char *) magic, 4) != 4)
817 return COMPRESSION_NONE;
819 /* GZIP_MAGIC and OLD_GZIP_MAGIC */
820 if (magic[0] == 037 && (magic[1] == 0213 || magic[1] == 0236))
822 return COMPRESSION_GZIP;
825 /* PKZIP_MAGIC */
826 if (magic[0] == 0120 && magic[1] == 0113 && magic[2] == 003 && magic[3] == 004)
828 /* Read compression type */
829 mc_lseek (fd, 8, SEEK_SET);
830 if (mc_read (fd, (char *) magic, 2) != 2)
831 return COMPRESSION_NONE;
833 /* Gzip can handle only deflated (8) or stored (0) files */
834 if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
835 return COMPRESSION_NONE;
837 /* Compatible with gzip */
838 return COMPRESSION_GZIP;
841 /* PACK_MAGIC and LZH_MAGIC and compress magic */
842 if (magic[0] == 037 && (magic[1] == 036 || magic[1] == 0240 || magic[1] == 0235))
844 /* Compatible with gzip */
845 return COMPRESSION_GZIP;
848 /* BZIP and BZIP2 files */
849 if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
851 switch (magic[2])
853 case '0':
854 return COMPRESSION_BZIP;
855 case 'h':
856 return COMPRESSION_BZIP2;
860 /* Support for LZMA (only utils format with magic in header).
861 * This is the default format of LZMA utils 4.32.1 and later. */
863 if (mc_read (fd, (char *) magic + 4, 2) != 2)
864 return COMPRESSION_NONE;
866 /* LZMA utils format */
867 if (magic[0] == 0xFF
868 && magic[1] == 'L'
869 && magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A' && magic[5] == 0x00)
870 return COMPRESSION_LZMA;
872 /* XZ compression magic */
873 if (magic[0] == 0xFD
874 && magic[1] == 0x37
875 && magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
876 return COMPRESSION_XZ;
878 str_len = strlen (name);
879 /* HACK: we must belive to extension of LZMA file :) ... */
880 if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0) ||
881 (str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
882 return COMPRESSION_LZMA;
884 return COMPRESSION_NONE;
887 /* --------------------------------------------------------------------------------------------- */
889 const char *
890 decompress_extension (int type)
892 switch (type)
894 case COMPRESSION_GZIP:
895 return "/ugz" VFS_PATH_URL_DELIMITER;
896 case COMPRESSION_BZIP:
897 return "/ubz" VFS_PATH_URL_DELIMITER;
898 case COMPRESSION_BZIP2:
899 return "/ubz2" VFS_PATH_URL_DELIMITER;
900 case COMPRESSION_LZMA:
901 return "/ulzma" VFS_PATH_URL_DELIMITER;
902 case COMPRESSION_XZ:
903 return "/uxz" VFS_PATH_URL_DELIMITER;
905 /* Should never reach this place */
906 fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
907 return 0;
910 /* --------------------------------------------------------------------------------------------- */
912 void
913 wipe_password (char *passwd)
915 char *p = passwd;
917 if (!p)
918 return;
919 for (; *p; p++)
920 *p = 0;
921 g_free (passwd);
924 /* --------------------------------------------------------------------------------------------- */
926 * Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key
928 * @param p pointer to string
930 * @return newly allocated string
933 char *
934 convert_controls (const char *p)
936 char *valcopy = g_strdup (p);
937 char *q;
939 /* Parse the escape special character */
940 for (q = valcopy; *p;)
942 if (*p == '\\')
944 p++;
945 if ((*p == 'e') || (*p == 'E'))
947 p++;
948 *q++ = ESC_CHAR;
951 else
953 if (*p == '^')
955 p++;
956 if (*p == '^')
957 *q++ = *p++;
958 else
960 char c = (*p | 0x20);
961 if (c >= 'a' && c <= 'z')
963 *q++ = c - 'a' + 1;
964 p++;
966 else if (*p)
967 p++;
970 else
971 *q++ = *p++;
974 *q = 0;
975 return valcopy;
978 /* --------------------------------------------------------------------------------------------- */
980 * Finds out a relative path from first to second, i.e. goes as many ..
981 * as needed up in first and then goes down using second
984 char *
985 diff_two_paths (const vfs_path_t * vpath1, const vfs_path_t * vpath2)
987 char *p, *q, *r, *s, *buf = NULL;
988 int i, j, prevlen = -1, currlen;
989 char *my_first = NULL, *my_second = NULL;
991 my_first = resolve_symlinks (vpath1);
992 if (my_first == NULL)
993 goto ret;
995 my_second = resolve_symlinks (vpath2);
996 if (my_second == NULL)
997 goto ret;
999 for (j = 0; j < 2; j++)
1001 p = my_first;
1002 q = my_second;
1003 while (TRUE)
1005 r = strchr (p, PATH_SEP);
1006 s = strchr (q, PATH_SEP);
1007 if (r == NULL || s == NULL)
1008 break;
1009 *r = '\0';
1010 *s = '\0';
1011 if (strcmp (p, q) != 0)
1013 *r = PATH_SEP;
1014 *s = PATH_SEP;
1015 break;
1018 *r = PATH_SEP;
1019 *s = PATH_SEP;
1021 p = r + 1;
1022 q = s + 1;
1024 p--;
1025 for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++)
1027 currlen = (i + 1) * 3 + strlen (q) + 1;
1028 if (j != 0)
1030 if (currlen < prevlen)
1031 g_free (buf);
1032 else
1033 goto ret;
1035 p = buf = g_malloc (currlen);
1036 prevlen = currlen;
1037 for (; i >= 0; i--, p += 3)
1038 strcpy (p, "../");
1039 strcpy (p, q);
1042 ret:
1043 g_free (my_first);
1044 g_free (my_second);
1045 return buf;
1048 /* --------------------------------------------------------------------------------------------- */
1050 * Append text to GList, remove all entries with the same text
1053 GList *
1054 list_append_unique (GList * list, char *text)
1056 GList *lc_link;
1059 * Go to the last position and traverse the list backwards
1060 * starting from the second last entry to make sure that we
1061 * are not removing the current link.
1063 list = g_list_append (list, text);
1064 list = g_list_last (list);
1065 lc_link = g_list_previous (list);
1067 while (lc_link != NULL)
1069 GList *newlink;
1071 newlink = g_list_previous (lc_link);
1072 if (strcmp ((char *) lc_link->data, text) == 0)
1074 GList *tmp;
1076 g_free (lc_link->data);
1077 tmp = g_list_remove_link (list, lc_link);
1078 (void) tmp;
1079 g_list_free_1 (lc_link);
1081 lc_link = newlink;
1084 return list;
1087 /* --------------------------------------------------------------------------------------------- */
1089 * Read and restore position for the given filename.
1090 * If there is no stored data, return line 1 and col 0.
1093 void
1094 load_file_position (const vfs_path_t * filename_vpath, long *line, long *column, off_t * offset,
1095 GArray ** bookmarks)
1097 char *fn;
1098 FILE *f;
1099 char buf[MC_MAXPATHLEN + 100];
1100 const size_t len = vfs_path_len (filename_vpath);
1102 /* defaults */
1103 *line = 1;
1104 *column = 0;
1105 *offset = 0;
1107 /* open file with positions */
1108 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1109 f = fopen (fn, "r");
1110 g_free (fn);
1111 if (f == NULL)
1112 return;
1114 /* prepare array for serialized bookmarks */
1115 if (bookmarks != NULL)
1116 *bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
1118 while (fgets (buf, sizeof (buf), f) != NULL)
1120 const char *p;
1121 gchar **pos_tokens;
1123 /* check if the filename matches the beginning of string */
1124 if (strncmp (buf, vfs_path_as_str (filename_vpath), len) != 0)
1125 continue;
1127 /* followed by single space */
1128 if (buf[len] != ' ')
1129 continue;
1131 /* and string without spaces */
1132 p = &buf[len + 1];
1133 if (strchr (p, ' ') != NULL)
1134 continue;
1136 pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
1137 if (pos_tokens[0] == NULL)
1139 *line = 1;
1140 *column = 0;
1141 *offset = 0;
1143 else
1145 *line = strtol (pos_tokens[0], NULL, 10);
1146 if (pos_tokens[1] == NULL)
1148 *column = 0;
1149 *offset = 0;
1151 else
1153 *column = strtol (pos_tokens[1], NULL, 10);
1154 if (pos_tokens[2] == NULL)
1155 *offset = 0;
1156 else if (bookmarks != NULL)
1158 size_t i;
1160 *offset = (off_t) g_ascii_strtoll (pos_tokens[2], NULL, 10);
1162 for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
1164 size_t val;
1166 val = strtoul (pos_tokens[3 + i], NULL, 10);
1167 g_array_append_val (*bookmarks, val);
1173 g_strfreev (pos_tokens);
1176 fclose (f);
1179 /* --------------------------------------------------------------------------------------------- */
1181 * Save position for the given file
1184 void
1185 save_file_position (const vfs_path_t * filename_vpath, long line, long column, off_t offset,
1186 GArray * bookmarks)
1188 static size_t filepos_max_saved_entries = 0;
1189 char *fn, *tmp_fn;
1190 FILE *f, *tmp_f;
1191 char buf[MC_MAXPATHLEN + 100];
1192 size_t i;
1193 const size_t len = vfs_path_len (filename_vpath);
1194 gboolean src_error = FALSE;
1196 if (filepos_max_saved_entries == 0)
1197 filepos_max_saved_entries = mc_config_get_int (mc_main_config, CONFIG_APP_SECTION,
1198 "filepos_max_saved_entries", 1024);
1200 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1201 if (fn == NULL)
1202 goto early_error;
1204 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
1206 /* open file */
1207 f = fopen (fn, "w");
1208 if (f == NULL)
1209 goto open_target_error;
1211 tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
1212 tmp_f = fopen (tmp_fn, "r");
1213 if (tmp_f == NULL)
1215 src_error = TRUE;
1216 goto open_source_error;
1219 /* put the new record */
1220 if (line != 1 || column != 0 || bookmarks != NULL)
1222 if (fprintf
1223 (f, "%s %ld;%ld;%" PRIuMAX, vfs_path_as_str (filename_vpath), line, column,
1224 (uintmax_t) offset) < 0)
1225 goto write_position_error;
1226 if (bookmarks != NULL)
1227 for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
1228 if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
1229 goto write_position_error;
1231 if (fprintf (f, "\n") < 0)
1232 goto write_position_error;
1235 i = 1;
1236 while (fgets (buf, sizeof (buf), tmp_f) != NULL)
1238 if (buf[len] == ' ' && strncmp (buf, vfs_path_as_str (filename_vpath), len) == 0
1239 && strchr (&buf[len + 1], ' ') == NULL)
1240 continue;
1242 fprintf (f, "%s", buf);
1243 if (++i > filepos_max_saved_entries)
1244 break;
1247 write_position_error:
1248 fclose (tmp_f);
1249 open_source_error:
1250 g_free (tmp_fn);
1251 fclose (f);
1252 if (src_error)
1253 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
1254 else
1255 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
1256 open_target_error:
1257 g_free (fn);
1258 early_error:
1259 if (bookmarks != NULL)
1260 g_array_free (bookmarks, TRUE);
1263 /* --------------------------------------------------------------------------------------------- */
1265 extern int
1266 ascii_alpha_to_cntrl (int ch)
1268 if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
1270 ch &= 0x1f;
1272 return ch;
1275 /* --------------------------------------------------------------------------------------------- */
1277 const char *
1278 Q_ (const char *s)
1280 const char *result, *sep;
1282 result = _(s);
1283 sep = strchr (result, '|');
1284 return (sep != NULL) ? sep + 1 : result;
1287 /* --------------------------------------------------------------------------------------------- */
1289 gboolean
1290 mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
1292 struct stat stat_buf;
1293 char *backup_path;
1294 gboolean ret;
1295 if (!exist_file (file_name))
1296 return FALSE;
1298 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1300 if (backup_path == NULL)
1301 return FALSE;
1303 ret = mc_util_write_backup_content (file_name, backup_path);
1305 if (ret)
1307 /* Backup file will have same ownership with main file. */
1308 if (stat (file_name, &stat_buf) == 0)
1309 chmod (backup_path, stat_buf.st_mode);
1310 else
1311 chmod (backup_path, S_IRUSR | S_IWUSR);
1314 g_free (backup_path);
1316 return ret;
1319 /* --------------------------------------------------------------------------------------------- */
1321 gboolean
1322 mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
1324 gboolean ret;
1325 char *backup_path;
1327 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1328 if (backup_path == NULL)
1329 return FALSE;
1331 ret = mc_util_write_backup_content (backup_path, file_name);
1332 g_free (backup_path);
1334 return ret;
1337 /* --------------------------------------------------------------------------------------------- */
1339 gboolean
1340 mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
1342 char *backup_path;
1344 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1345 if (backup_path == NULL)
1346 return FALSE;
1348 if (exist_file (backup_path))
1350 vfs_path_t *vpath;
1352 vpath = vfs_path_from_str (backup_path);
1353 mc_unlink (vpath);
1354 vfs_path_free (vpath);
1357 g_free (backup_path);
1358 return TRUE;
1361 /* --------------------------------------------------------------------------------------------- */
1363 * partly taken from dcigettext.c, returns "" for default locale
1364 * value should be freed by calling function g_free()
1367 char *
1368 guess_message_value (void)
1370 static const char *const var[] = {
1371 /* Setting of LC_ALL overwrites all other. */
1372 /* Do not use LANGUAGE for check user locale and drowing hints */
1373 "LC_ALL",
1374 /* Next comes the name of the desired category. */
1375 "LC_MESSAGES",
1376 /* Last possibility is the LANG environment variable. */
1377 "LANG",
1378 /* NULL exit loops */
1379 NULL
1382 unsigned i = 0;
1383 const char *locale = NULL;
1385 while (var[i] != NULL)
1387 locale = getenv (var[i]);
1388 if (locale != NULL && locale[0] != '\0')
1389 break;
1390 i++;
1393 if (locale == NULL)
1394 locale = "";
1396 return g_strdup (locale);
1399 /* --------------------------------------------------------------------------------------------- */