This source file includes following definitions.
- is_7bit_printable
- is_iso_printable
- is_8bit_printable
- resolve_symlinks
- mc_util_write_backup_content
- is_printable
- name_quote
- fake_name_quote
- path_trunc
- size_trunc
- size_trunc_sep
- size_trunc_len
- string_perm
- extension
- load_mc_home_file
- extract_line
- x_basename
- unix_error_string
- skip_separators
- skip_numbers
- strip_ctrl_codes
- get_compression_type
- decompress_extension
- wipe_password
- convert_controls
- diff_two_paths
- list_append_unique
- load_file_position
- save_file_position
- ascii_alpha_to_cntrl
- Q_
- mc_util_make_backup_if_possible
- mc_util_restore_from_backup_if_possible
- mc_util_unlink_backup_if_possible
- guess_message_value
- mc_get_profile_root
- mc_propagate_error
- mc_replace_error
- mc_time_elapsed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #include <config.h>
36
37 #include <ctype.h>
38 #include <stddef.h>
39 #include <limits.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47
48 #include "lib/global.h"
49 #include "lib/mcconfig.h"
50 #include "lib/fileloc.h"
51 #include "lib/vfs/vfs.h"
52 #include "lib/strutil.h"
53 #include "lib/util.h"
54
55
56
57
58
59 #define ismode(n, m) ((n & m) == m)
60
61
62 #ifndef TMP_MAX
63 # define TMP_MAX 16384
64 #endif
65
66 #define TMP_SUFFIX ".tmp"
67
68 #define ASCII_A (0x40 + 1)
69 #define ASCII_Z (0x40 + 26)
70 #define ASCII_a (0x60 + 1)
71 #define ASCII_z (0x60 + 26)
72
73
74
75
76
77
78
79
80
81
82
83 #ifndef HAVE_CHARSET
84 static inline int
85 is_7bit_printable (unsigned char c)
86 {
87 return (c > 31 && c < 127);
88 }
89 #endif
90
91
92
93 static inline int
94 is_iso_printable (unsigned char c)
95 {
96 return ((c > 31 && c < 127) || c >= 160);
97 }
98
99
100
101 static inline int
102 is_8bit_printable (unsigned char c)
103 {
104
105 if (mc_global.tty.xterm_flag)
106 return is_iso_printable (c);
107
108 return (c > 31 && c != 127 && c != 155);
109 }
110
111
112
113 static char *
114 resolve_symlinks (const vfs_path_t *vpath)
115 {
116 char *p, *p2;
117 char *buf, *buf2, *q, *r, c;
118 struct stat mybuf;
119
120 if (vpath->relative)
121 return NULL;
122
123 p = p2 = g_strdup (vfs_path_as_str (vpath));
124 r = buf = g_malloc (MC_MAXPATHLEN);
125 buf2 = g_malloc (MC_MAXPATHLEN);
126 *r++ = PATH_SEP;
127 *r = '\0';
128
129 do
130 {
131 q = strchr (p + 1, PATH_SEP);
132 if (q == NULL)
133 {
134 q = strchr (p + 1, '\0');
135 if (q == p + 1)
136 break;
137 }
138 c = *q;
139 *q = '\0';
140 if (mc_lstat (vpath, &mybuf) < 0)
141 {
142 MC_PTR_FREE (buf);
143 goto ret;
144 }
145 if (!S_ISLNK (mybuf.st_mode))
146 strcpy (r, p + 1);
147 else
148 {
149 int len;
150
151 len = mc_readlink (vpath, buf2, MC_MAXPATHLEN - 1);
152 if (len < 0)
153 {
154 MC_PTR_FREE (buf);
155 goto ret;
156 }
157 buf2[len] = '\0';
158 if (IS_PATH_SEP (*buf2))
159 strcpy (buf, buf2);
160 else
161 strcpy (r, buf2);
162 }
163 canonicalize_pathname (buf);
164 r = strchr (buf, '\0');
165 if (*r == '\0' || !IS_PATH_SEP (r[-1]))
166
167 {
168 *r++ = PATH_SEP;
169 *r = '\0';
170 }
171 *q = c;
172 p = q;
173 }
174 while (c != '\0');
175
176 if (*buf == '\0')
177 strcpy (buf, PATH_SEP_STR);
178 else if (IS_PATH_SEP (r[-1]) && r != buf + 1)
179 r[-1] = '\0';
180
181 ret:
182 g_free (buf2);
183 g_free (p2);
184 return buf;
185 }
186
187
188
189 static gboolean
190 mc_util_write_backup_content (const char *from_file_name, const char *to_file_name)
191 {
192 FILE *backup_fd;
193 char *contents;
194 gsize length;
195 gboolean ret1 = TRUE;
196
197 if (!g_file_get_contents (from_file_name, &contents, &length, NULL))
198 return FALSE;
199
200 backup_fd = fopen (to_file_name, "w");
201 if (backup_fd == NULL)
202 {
203 g_free (contents);
204 return FALSE;
205 }
206
207 if (fwrite ((const void *) contents, 1, length, backup_fd) != length)
208 ret1 = FALSE;
209
210 {
211 int ret2;
212
213
214 ret2 = fflush (backup_fd);
215
216 ret2 = fclose (backup_fd);
217 (void) ret2;
218 }
219
220 g_free (contents);
221 return ret1;
222 }
223
224
225
226
227
228 int
229 is_printable (int c)
230 {
231 c &= 0xff;
232
233 #ifdef HAVE_CHARSET
234
235
236 return is_8bit_printable (c);
237 #else
238 if (!mc_global.eight_bit_clean)
239 return is_7bit_printable (c);
240
241 if (mc_global.full_eight_bits)
242 return is_8bit_printable (c);
243
244 return is_iso_printable (c);
245 #endif
246 }
247
248
249
250
251
252
253
254 char *
255 name_quote (const char *s, gboolean quote_percent)
256 {
257 GString *ret;
258
259 if (s == NULL || *s == '\0')
260 return NULL;
261
262 ret = g_string_sized_new (64);
263
264 if (*s == '-')
265 g_string_append (ret, "." PATH_SEP_STR);
266
267 for (; *s != '\0'; s++)
268 {
269 switch (*s)
270 {
271 case '%':
272 if (quote_percent)
273 g_string_append_c (ret, '%');
274 break;
275 case '\'':
276 case '\\':
277 case '\r':
278 case '\n':
279 case '\t':
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 case '(':
297 case ')':
298 g_string_append_c (ret, '\\');
299 break;
300 case '~':
301 case '#':
302 if (ret->len == 0)
303 g_string_append_c (ret, '\\');
304 break;
305 default:
306 break;
307 }
308 g_string_append_c (ret, *s);
309 }
310
311 return g_string_free (ret, ret->len == 0);
312 }
313
314
315
316 char *
317 fake_name_quote (const char *s, gboolean quote_percent)
318 {
319 (void) quote_percent;
320
321 return (s == NULL || *s == '\0' ? NULL : g_strdup (s));
322 }
323
324
325
326
327
328
329
330
331 const char *
332 path_trunc (const char *path, size_t trunc_len)
333 {
334 vfs_path_t *vpath;
335 const char *ret;
336
337 vpath = vfs_path_from_str_flags (path, VPF_STRIP_PASSWORD);
338 ret = str_trunc (vfs_path_as_str (vpath), trunc_len);
339 vfs_path_free (vpath, TRUE);
340
341 return ret;
342 }
343
344
345
346 const char *
347 size_trunc (uintmax_t size, gboolean use_si)
348 {
349 static char x[BUF_TINY];
350 uintmax_t divisor = 1;
351 const char *xtra = _ ("B");
352
353 if (size > 999999999UL)
354 {
355 divisor = use_si ? 1000 : 1024;
356 xtra = use_si ? _ ("kB") : _ ("KiB");
357
358 if (size / divisor > 999999999UL)
359 {
360 divisor = use_si ? (1000 * 1000) : (1024 * 1024);
361 xtra = use_si ? _ ("MB") : _ ("MiB");
362
363 if (size / divisor > 999999999UL)
364 {
365 divisor = use_si ? (1000 * 1000 * 1000) : (1024 * 1024 * 1024);
366 xtra = use_si ? _ ("GB") : _ ("GiB");
367 }
368 }
369 }
370 g_snprintf (x, sizeof (x), "%.0f %s", 1.0 * size / divisor, xtra);
371 return x;
372 }
373
374
375
376 const char *
377 size_trunc_sep (uintmax_t size, gboolean use_si)
378 {
379 static char x[60];
380 int count;
381 const char *p, *y;
382 char *d;
383
384 p = y = size_trunc (size, use_si);
385 p += strlen (p) - 1;
386 d = x + sizeof (x) - 1;
387 *d-- = '\0';
388
389
390 while (p >= y && !g_ascii_isdigit (*p))
391 *d-- = *p--;
392 for (count = 0; p >= y; count++)
393 {
394 if (count == 3)
395 {
396 *d-- = ',';
397 count = 0;
398 }
399 *d-- = *p--;
400 }
401 d++;
402 if (*d == ',')
403 d++;
404 return d;
405 }
406
407
408
409
410
411
412
413
414
415
416
417
418 void
419 size_trunc_len (char *buffer, unsigned int len, uintmax_t size, int units, gboolean use_si)
420 {
421
422 static const uintmax_t power10[] = {
423
424 1ULL,
425 10ULL,
426 100ULL,
427 1000ULL,
428 10000ULL,
429 100000ULL,
430 1000000ULL,
431 10000000ULL,
432 100000000ULL,
433 1000000000ULL
434
435
436
437 #if SIZEOF_UINTMAX_T == 8
438 ,
439 10000000000ULL,
440 100000000000ULL,
441 1000000000000ULL,
442 10000000000000ULL,
443 100000000000000ULL,
444 1000000000000000ULL,
445 10000000000000000ULL,
446 100000000000000000ULL,
447 1000000000000000000ULL,
448 10000000000000000000ULL,
449
450
451
452 #endif
453 };
454
455 static const char *const suffix[] = {
456 "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", NULL
457 };
458 static const char *const suffix_lc[] = {
459 "", "k", "m", "g", "t", "p", "e", "z", "y", "r", "q", NULL,
460 };
461
462 static int sfx_last = -1;
463
464 const char *const *sfx = use_si ? suffix_lc : suffix;
465 int j = 0;
466
467 if (sfx_last < 0)
468 {
469 for (sfx_last = 0; sfx[sfx_last] != NULL; sfx_last++)
470 ;
471
472 sfx_last--;
473 }
474
475 if (len == 0)
476 len = 9;
477 #if SIZEOF_UINTMAX_T == 8
478
479 else if (len > 19)
480 len = 19;
481 #else
482
483 else if (len > 9)
484 len = 9;
485 #endif
486
487 const int units_safe = MIN (units, sfx_last);
488
489
490
491
492
493
494 if (use_si)
495 for (j = 0; j < units_safe; j++)
496 {
497 uintmax_t size_remain;
498
499 size_remain = ((size % 125) * 1024) / 1000;
500 size /= 125;
501 size *= 128;
502 size += size_remain;
503 }
504
505 for (j = units_safe; sfx[j] != NULL; j++)
506 {
507 if (size == 0)
508 {
509 if (j == units)
510 {
511
512 g_snprintf (buffer, len + 1, "%s", "0");
513 }
514 else
515 {
516
517 g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", (j > 1) ? sfx[j - 1] : "B");
518 }
519 break;
520 }
521
522 if (size < power10[len - (j > 0 ? 1 : 0)])
523 {
524 g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, sfx[j]);
525 break;
526 }
527
528
529 if (use_si)
530 size = (size + 500) / 1000;
531 else
532 size = (size + 512) >> 10;
533 }
534 }
535
536
537
538 const char *
539 string_perm (mode_t mode_bits)
540 {
541 static char mode[11];
542
543 strcpy (mode, "----------");
544 if (S_ISDIR (mode_bits))
545 mode[0] = 'd';
546 if (S_ISCHR (mode_bits))
547 mode[0] = 'c';
548 if (S_ISBLK (mode_bits))
549 mode[0] = 'b';
550 if (S_ISLNK (mode_bits))
551 mode[0] = 'l';
552 if (S_ISFIFO (mode_bits))
553 mode[0] = 'p';
554 if (S_ISNAM (mode_bits))
555 mode[0] = 'n';
556 if (S_ISSOCK (mode_bits))
557 mode[0] = 's';
558 if (S_ISDOOR (mode_bits))
559 mode[0] = 'D';
560 if (ismode (mode_bits, S_IXOTH))
561 mode[9] = 'x';
562 if (ismode (mode_bits, S_IWOTH))
563 mode[8] = 'w';
564 if (ismode (mode_bits, S_IROTH))
565 mode[7] = 'r';
566 if (ismode (mode_bits, S_IXGRP))
567 mode[6] = 'x';
568 if (ismode (mode_bits, S_IWGRP))
569 mode[5] = 'w';
570 if (ismode (mode_bits, S_IRGRP))
571 mode[4] = 'r';
572 if (ismode (mode_bits, S_IXUSR))
573 mode[3] = 'x';
574 if (ismode (mode_bits, S_IWUSR))
575 mode[2] = 'w';
576 if (ismode (mode_bits, S_IRUSR))
577 mode[1] = 'r';
578 #ifdef S_ISUID
579 if (ismode (mode_bits, S_ISUID))
580 mode[3] = (mode[3] == 'x') ? 's' : 'S';
581 #endif
582 #ifdef S_ISGID
583 if (ismode (mode_bits, S_ISGID))
584 mode[6] = (mode[6] == 'x') ? 's' : 'S';
585 #endif
586 #ifdef S_ISVTX
587 if (ismode (mode_bits, S_ISVTX))
588 mode[9] = (mode[9] == 'x') ? 't' : 'T';
589 #endif
590 return mode;
591 }
592
593
594
595 const char *
596 extension (const char *filename)
597 {
598 const char *d;
599
600 d = strrchr (filename, '.');
601
602 return d != NULL ? d + 1 : "";
603 }
604
605
606
607 char *
608 load_mc_home_file (const char *from, const char *filename, char **allocated_filename,
609 size_t *length)
610 {
611 char *hintfile_base, *hintfile;
612 char *lang;
613 char *data;
614
615 hintfile_base = g_build_filename (from, filename, (char *) NULL);
616 lang = guess_message_value ();
617
618 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
619 if (!g_file_get_contents (hintfile, &data, length, NULL))
620 {
621
622 if (lang[0] != '\0' && lang[1] != '\0')
623 lang[2] = '\0';
624 g_free (hintfile);
625 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
626 if (!g_file_get_contents (hintfile, &data, length, NULL))
627 {
628 g_free (hintfile);
629 hintfile = hintfile_base;
630 g_file_get_contents (hintfile_base, &data, length, NULL);
631 }
632 }
633
634 g_free (lang);
635
636 if (hintfile != hintfile_base)
637 g_free (hintfile_base);
638
639 if (allocated_filename != NULL)
640 *allocated_filename = hintfile;
641 else
642 g_free (hintfile);
643
644 return data;
645 }
646
647
648
649 const char *
650 extract_line (const char *s, const char *top, size_t *len)
651 {
652 static char tmp_line[BUF_MEDIUM];
653 char *t = tmp_line;
654
655 while (*s != '\0' && *s != '\n' && (size_t) (t - tmp_line) < sizeof (tmp_line) - 1 && s < top)
656 *t++ = *s++;
657 *t = '\0';
658
659 if (len != NULL)
660 *len = (size_t) (t - tmp_line);
661
662 return tmp_line;
663 }
664
665
666
667
668
669
670 const char *
671 x_basename (const char *s)
672 {
673 const char *url_delim, *path_sep;
674
675 url_delim = g_strrstr (s, VFS_PATH_URL_DELIMITER);
676 path_sep = strrchr (s, PATH_SEP);
677
678 if (path_sep == NULL)
679 return s;
680
681 if (url_delim == NULL || url_delim < path_sep - strlen (VFS_PATH_URL_DELIMITER)
682 || url_delim - s + strlen (VFS_PATH_URL_DELIMITER) < strlen (s))
683 {
684
685 if (!IS_PATH_SEP (s[strlen (s) - 1]))
686 return path_sep + 1;
687
688 while (--path_sep > s && !IS_PATH_SEP (*path_sep))
689 ;
690 return (path_sep != s) ? path_sep + 1 : s;
691 }
692
693 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
694 ;
695 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
696 ;
697
698 return url_delim == s ? s : url_delim + 1;
699 }
700
701
702
703 const char *
704 unix_error_string (int error_num)
705 {
706 static char buffer[BUF_LARGE];
707 gchar *strerror_currentlocale;
708
709 strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
710 g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
711 g_free (strerror_currentlocale);
712
713 return buffer;
714 }
715
716
717
718 const char *
719 skip_separators (const char *s)
720 {
721 const char *su = s;
722
723 for (; *su != '\0'; str_cnext_char (&su))
724 if (!whitespace (*su) && *su != ',')
725 break;
726
727 return su;
728 }
729
730
731
732 const char *
733 skip_numbers (const char *s)
734 {
735 const char *su = s;
736
737 for (; *su != '\0'; str_cnext_char (&su))
738 if (!str_isdigit (su))
739 break;
740
741 return su;
742 }
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762 char *
763 strip_ctrl_codes (char *s)
764 {
765 char *w;
766 char *r;
767
768 if (s == NULL)
769 return NULL;
770
771 for (w = s, r = s; *r != '\0';)
772 {
773 if (*r == ESC_CHAR)
774 {
775
776
777 if (*(++r) == '[' || *r == '(')
778 {
779
780 while (*(++r) != '\0' && strchr ("0123456789;:<=>?", *r) != NULL)
781 ;
782 while (*r != '\0' && (*r < 0x40 || *r > 0x7E))
783 ++r;
784 }
785 else if (*r == ']')
786 {
787
788
789
790
791
792
793 char *new_r;
794
795 for (new_r = r; *new_r != '\0'; new_r++)
796 {
797 switch (*new_r)
798 {
799
800 case '\a':
801 r = new_r;
802 goto osc_out;
803 case ESC_CHAR:
804
805 if (new_r[1] == '\\')
806 {
807 r = new_r + 1;
808 goto osc_out;
809 }
810 break;
811 default:
812 break;
813 }
814 }
815 osc_out:;
816 }
817
818
819
820
821
822 if (*r != '\0')
823 r++;
824 }
825 else
826 {
827 char *n;
828
829 n = str_get_next_char (r);
830 if (str_isprint (r))
831 {
832 memmove (w, r, n - r);
833 w += n - r;
834 }
835 r = n;
836 }
837 }
838
839 *w = '\0';
840 return s;
841 }
842
843
844
845 enum compression_type
846 get_compression_type (int fd, const char *name)
847 {
848 unsigned char magic[16];
849 size_t str_len;
850
851
852 if (mc_read (fd, (char *) magic, 4) != 4)
853 return COMPRESSION_NONE;
854
855
856 if (magic[0] == 0x1F && (magic[1] == 0x8B || magic[1] == 0x9E))
857 return COMPRESSION_GZIP;
858
859
860 if (magic[0] == 'P' && magic[1] == 'K' && magic[2] == 0x03 && magic[3] == 0x04)
861 {
862
863 mc_lseek (fd, 8, SEEK_SET);
864 if (mc_read (fd, (char *) magic, 2) != 2)
865 return COMPRESSION_NONE;
866
867 if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
868 return COMPRESSION_NONE;
869
870 return COMPRESSION_ZIP;
871 }
872
873
874 if (magic[0] == 0x1F && (magic[1] == 0x1E || magic[1] == 0xA0 || magic[1] == 0x9D))
875
876 return COMPRESSION_GZIP;
877
878
879 if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
880 switch (magic[2])
881 {
882 case '0':
883 return COMPRESSION_BZIP;
884 case 'h':
885 return COMPRESSION_BZIP2;
886 default:
887 break;
888 }
889
890
891 if (magic[0] == 0x04 && magic[1] == 0x22 && magic[2] == 0x4d && magic[3] == 0x18)
892 return COMPRESSION_LZ4;
893
894 if (mc_read (fd, (char *) magic + 4, 2) != 2)
895 return COMPRESSION_NONE;
896
897
898 if (magic[0] == 'L' && magic[1] == 'Z' && magic[2] == 'I' && magic[3] == 'P'
899 && (magic[4] == 0x00 || magic[4] == 0x01))
900 return COMPRESSION_LZIP;
901
902
903
904 if (magic[0] == 0xFF && magic[1] == 'L' && magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A'
905 && magic[5] == 0x00)
906 return COMPRESSION_LZMA;
907
908
909 if (magic[0] == 0x89 && magic[1] == 0x4c && magic[2] == 0x5a && magic[3] == 0x4f
910 && magic[4] == 0x00 && magic[5] == 0x0d)
911 return COMPRESSION_LZO;
912
913
914 if (magic[0] == 0xFD && magic[1] == 0x37 && magic[2] == 0x7A && magic[3] == 0x58
915 && magic[4] == 0x5A && magic[5] == 0x00)
916 return COMPRESSION_XZ;
917
918 if (magic[0] == 0x28 && magic[1] == 0xB5 && magic[2] == 0x2F && magic[3] == 0xFD)
919 return COMPRESSION_ZSTD;
920
921 str_len = strlen (name);
922
923 if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0)
924 || (str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
925 return COMPRESSION_LZMA;
926
927 return COMPRESSION_NONE;
928 }
929
930
931
932 const char *
933 decompress_extension (int type)
934 {
935 switch (type)
936 {
937 case COMPRESSION_ZIP:
938 return "/uz" VFS_PATH_URL_DELIMITER;
939 case COMPRESSION_GZIP:
940 return "/ugz" VFS_PATH_URL_DELIMITER;
941 case COMPRESSION_BZIP:
942 return "/ubz" VFS_PATH_URL_DELIMITER;
943 case COMPRESSION_BZIP2:
944 return "/ubz2" VFS_PATH_URL_DELIMITER;
945 case COMPRESSION_LZIP:
946 return "/ulz" VFS_PATH_URL_DELIMITER;
947 case COMPRESSION_LZ4:
948 return "/ulz4" VFS_PATH_URL_DELIMITER;
949 case COMPRESSION_LZMA:
950 return "/ulzma" VFS_PATH_URL_DELIMITER;
951 case COMPRESSION_LZO:
952 return "/ulzo" VFS_PATH_URL_DELIMITER;
953 case COMPRESSION_XZ:
954 return "/uxz" VFS_PATH_URL_DELIMITER;
955 case COMPRESSION_ZSTD:
956 return "/uzst" VFS_PATH_URL_DELIMITER;
957 default:
958 break;
959 }
960
961 fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
962 return 0;
963 }
964
965
966
967 void
968 wipe_password (char *passwd)
969 {
970 if (passwd != NULL)
971 {
972 char *p;
973
974 for (p = passwd; *p != '\0'; p++)
975 *p = '\0';
976 g_free (passwd);
977 }
978 }
979
980
981
982
983
984
985
986
987
988
989 char *
990 convert_controls (const char *p)
991 {
992 char *valcopy;
993 char *q;
994
995 valcopy = g_strdup (p);
996
997
998 for (q = valcopy; *p != '\0';)
999 switch (*p)
1000 {
1001 case '\\':
1002 p++;
1003
1004 if (*p == 'e' || *p == 'E')
1005 {
1006 p++;
1007 *q++ = ESC_CHAR;
1008 }
1009 break;
1010
1011 case '^':
1012 p++;
1013 if (*p == '^')
1014 *q++ = *p++;
1015 else
1016 {
1017 char c;
1018
1019 c = *p | 0x20;
1020 if (c >= 'a' && c <= 'z')
1021 {
1022 *q++ = c - 'a' + 1;
1023 p++;
1024 }
1025 else if (*p != '\0')
1026 p++;
1027 }
1028 break;
1029
1030 default:
1031 *q++ = *p++;
1032 }
1033
1034 *q = '\0';
1035 return valcopy;
1036 }
1037
1038
1039
1040
1041
1042
1043
1044 char *
1045 diff_two_paths (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
1046 {
1047 int j, prevlen = -1, currlen;
1048 char *my_first = NULL, *my_second = NULL;
1049 char *buf = NULL;
1050
1051 my_first = resolve_symlinks (vpath1);
1052 if (my_first == NULL)
1053 goto ret;
1054
1055 my_second = resolve_symlinks (vpath2);
1056 if (my_second == NULL)
1057 goto ret;
1058
1059 for (j = 0; j < 2; j++)
1060 {
1061 char *p, *q;
1062 int i;
1063
1064 p = my_first;
1065 q = my_second;
1066
1067 while (TRUE)
1068 {
1069 char *r, *s;
1070 ptrdiff_t len;
1071
1072 r = strchr (p, PATH_SEP);
1073 if (r == NULL)
1074 break;
1075 s = strchr (q, PATH_SEP);
1076 if (s == NULL)
1077 break;
1078
1079 len = r - p;
1080 if (len != (s - q) || strncmp (p, q, (size_t) len) != 0)
1081 break;
1082
1083 p = r + 1;
1084 q = s + 1;
1085 }
1086 p--;
1087 for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++)
1088 ;
1089 currlen = (i + 1) * 3 + strlen (q) + 1;
1090 if (j != 0)
1091 {
1092 if (currlen < prevlen)
1093 g_free (buf);
1094 else
1095 goto ret;
1096 }
1097 p = buf = g_malloc (currlen);
1098 prevlen = currlen;
1099 for (; i >= 0; i--, p += 3)
1100 strcpy (p, "../");
1101 strcpy (p, q);
1102 }
1103
1104 ret:
1105 g_free (my_first);
1106 g_free (my_second);
1107 return buf;
1108 }
1109
1110
1111
1112
1113
1114
1115 GList *
1116 list_append_unique (GList *list, char *text)
1117 {
1118 GList *lc_link;
1119
1120
1121
1122
1123
1124
1125 list = g_list_append (list, text);
1126 list = g_list_last (list);
1127 lc_link = g_list_previous (list);
1128
1129 while (lc_link != NULL)
1130 {
1131 GList *newlink;
1132
1133 newlink = g_list_previous (lc_link);
1134 if (strcmp ((char *) lc_link->data, text) == 0)
1135 {
1136 GList *tmp;
1137
1138 g_free (lc_link->data);
1139 tmp = g_list_remove_link (list, lc_link);
1140 (void) tmp;
1141 g_list_free_1 (lc_link);
1142 }
1143 lc_link = newlink;
1144 }
1145
1146 return list;
1147 }
1148
1149
1150
1151
1152
1153
1154
1155 void
1156 load_file_position (const vfs_path_t *filename_vpath, long *line, long *column, off_t *offset,
1157 GArray **bookmarks)
1158 {
1159 char *fn;
1160 FILE *f;
1161 char buf[MC_MAXPATHLEN + 100];
1162 const size_t len = vfs_path_len (filename_vpath);
1163
1164
1165 *line = 1;
1166 *column = 0;
1167 *offset = 0;
1168
1169
1170 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1171 f = fopen (fn, "r");
1172 g_free (fn);
1173 if (f == NULL)
1174 return;
1175
1176
1177 if (bookmarks != NULL)
1178 *bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
1179
1180 while (fgets (buf, sizeof (buf), f) != NULL)
1181 {
1182 const char *p;
1183 gchar **pos_tokens;
1184
1185
1186 if (strncmp (buf, vfs_path_as_str (filename_vpath), len) != 0)
1187 continue;
1188
1189
1190 if (buf[len] != ' ')
1191 continue;
1192
1193
1194 p = &buf[len + 1];
1195 if (strchr (p, ' ') != NULL)
1196 continue;
1197
1198 pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
1199 if (pos_tokens[0] == NULL)
1200 {
1201 *line = 1;
1202 *column = 0;
1203 *offset = 0;
1204 }
1205 else
1206 {
1207 *line = strtol (pos_tokens[0], NULL, 10);
1208 if (pos_tokens[1] == NULL)
1209 {
1210 *column = 0;
1211 *offset = 0;
1212 }
1213 else
1214 {
1215 *column = strtol (pos_tokens[1], NULL, 10);
1216 if (pos_tokens[2] == NULL)
1217 *offset = 0;
1218 else if (bookmarks != NULL)
1219 {
1220 size_t i;
1221
1222 *offset = (off_t) g_ascii_strtoll (pos_tokens[2], NULL, 10);
1223
1224 for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
1225 {
1226 size_t val;
1227
1228 val = strtoul (pos_tokens[3 + i], NULL, 10);
1229 g_array_append_val (*bookmarks, val);
1230 }
1231 }
1232 }
1233 }
1234
1235 g_strfreev (pos_tokens);
1236 }
1237
1238 fclose (f);
1239 }
1240
1241
1242
1243
1244
1245
1246 void
1247 save_file_position (const vfs_path_t *filename_vpath, long line, long column, off_t offset,
1248 GArray *bookmarks)
1249 {
1250 static size_t filepos_max_saved_entries = 0;
1251 char *fn, *tmp_fn;
1252 FILE *f, *tmp_f;
1253 char buf[MC_MAXPATHLEN + 100];
1254 size_t i;
1255 const size_t len = vfs_path_len (filename_vpath);
1256 gboolean src_error = FALSE;
1257
1258 if (filepos_max_saved_entries == 0)
1259 filepos_max_saved_entries = mc_config_get_int (mc_global.main_config, CONFIG_APP_SECTION,
1260 "filepos_max_saved_entries", 1024);
1261
1262 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1263 if (fn == NULL)
1264 goto early_error;
1265
1266 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
1267
1268
1269 f = fopen (fn, "w");
1270 if (f == NULL)
1271 goto open_target_error;
1272
1273 tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
1274 tmp_f = fopen (tmp_fn, "r");
1275 if (tmp_f == NULL)
1276 {
1277 src_error = TRUE;
1278 goto open_source_error;
1279 }
1280
1281
1282 if (line != 1 || column != 0 || bookmarks != NULL)
1283 {
1284 if (fprintf (f, "%s %ld;%ld;%" PRIuMAX, vfs_path_as_str (filename_vpath), line, column,
1285 (uintmax_t) offset)
1286 < 0)
1287 goto write_position_error;
1288 if (bookmarks != NULL)
1289 for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
1290 if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
1291 goto write_position_error;
1292
1293 if (fprintf (f, "\n") < 0)
1294 goto write_position_error;
1295 }
1296
1297 i = 1;
1298 while (fgets (buf, sizeof (buf), tmp_f) != NULL)
1299 {
1300 if (buf[len] == ' ' && strncmp (buf, vfs_path_as_str (filename_vpath), len) == 0
1301 && strchr (&buf[len + 1], ' ') == NULL)
1302 continue;
1303
1304 fprintf (f, "%s", buf);
1305 if (++i > filepos_max_saved_entries)
1306 break;
1307 }
1308
1309 write_position_error:
1310 fclose (tmp_f);
1311 open_source_error:
1312 g_free (tmp_fn);
1313 fclose (f);
1314 if (src_error)
1315 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
1316 else
1317 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
1318 open_target_error:
1319 g_free (fn);
1320 early_error:
1321 if (bookmarks != NULL)
1322 g_array_free (bookmarks, TRUE);
1323 }
1324
1325
1326
1327 extern int
1328 ascii_alpha_to_cntrl (int ch)
1329 {
1330 if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
1331 ch &= 0x1f;
1332
1333 return ch;
1334 }
1335
1336
1337
1338 const char *
1339 Q_ (const char *s)
1340 {
1341 const char *result, *sep;
1342
1343 result = _ (s);
1344 sep = strchr (result, '|');
1345
1346 return sep != NULL ? sep + 1 : result;
1347 }
1348
1349
1350
1351 gboolean
1352 mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
1353 {
1354 struct stat stat_buf;
1355 char *backup_path;
1356 gboolean ret;
1357
1358 if (!exist_file (file_name))
1359 return FALSE;
1360
1361 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1362 if (backup_path == NULL)
1363 return FALSE;
1364
1365 ret = mc_util_write_backup_content (file_name, backup_path);
1366 if (ret)
1367 {
1368
1369 if (stat (file_name, &stat_buf) == 0)
1370 chmod (backup_path, stat_buf.st_mode);
1371 else
1372 chmod (backup_path, S_IRUSR | S_IWUSR);
1373 }
1374
1375 g_free (backup_path);
1376
1377 return ret;
1378 }
1379
1380
1381
1382 gboolean
1383 mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
1384 {
1385 gboolean ret;
1386 char *backup_path;
1387
1388 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1389 if (backup_path == NULL)
1390 return FALSE;
1391
1392 ret = mc_util_write_backup_content (backup_path, file_name);
1393 g_free (backup_path);
1394
1395 return ret;
1396 }
1397
1398
1399
1400 gboolean
1401 mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
1402 {
1403 char *backup_path;
1404
1405 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1406 if (backup_path == NULL)
1407 return FALSE;
1408
1409 if (exist_file (backup_path))
1410 {
1411 vfs_path_t *vpath;
1412
1413 vpath = vfs_path_from_str (backup_path);
1414 mc_unlink (vpath);
1415 vfs_path_free (vpath, TRUE);
1416 }
1417
1418 g_free (backup_path);
1419 return TRUE;
1420 }
1421
1422
1423
1424
1425
1426
1427
1428 char *
1429 guess_message_value (void)
1430 {
1431 static const char *const var[] = {
1432
1433
1434 "LC_ALL",
1435
1436 "LC_MESSAGES",
1437
1438 "LANG",
1439
1440 NULL
1441 };
1442
1443 size_t i;
1444 const char *locale = NULL;
1445
1446 for (i = 0; var[i] != NULL; i++)
1447 {
1448 locale = getenv (var[i]);
1449 if (locale != NULL && locale[0] != '\0')
1450 break;
1451 }
1452
1453 if (locale == NULL)
1454 locale = "";
1455
1456 return g_strdup (locale);
1457 }
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468 const char *
1469 mc_get_profile_root (void)
1470 {
1471 static const char *profile_root = NULL;
1472
1473 if (profile_root == NULL)
1474 {
1475 profile_root = g_getenv ("MC_PROFILE_ROOT");
1476 if (profile_root == NULL || *profile_root == '\0')
1477 profile_root = mc_config_get_home_dir ();
1478 }
1479
1480 return profile_root;
1481 }
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493 void
1494 mc_propagate_error (GError **dest, int code, const char *format, ...)
1495 {
1496 if (dest != NULL && *dest == NULL)
1497 {
1498 GError *tmp_error;
1499 va_list args;
1500
1501 va_start (args, format);
1502 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1503 va_end (args);
1504
1505 g_propagate_error (dest, tmp_error);
1506 }
1507 }
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519 void
1520 mc_replace_error (GError **dest, int code, const char *format, ...)
1521 {
1522 if (dest != NULL)
1523 {
1524 GError *tmp_error;
1525 va_list args;
1526
1527 va_start (args, format);
1528 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1529 va_end (args);
1530
1531 g_error_free (*dest);
1532 *dest = NULL;
1533 g_propagate_error (dest, tmp_error);
1534 }
1535 }
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548 gboolean
1549 mc_time_elapsed (gint64 *timestamp, gint64 delay)
1550 {
1551 gint64 now;
1552
1553 now = g_get_monotonic_time ();
1554
1555 if (now >= *timestamp && now < *timestamp + delay)
1556 return FALSE;
1557
1558 *timestamp = now;
1559 return TRUE;
1560 }
1561
1562