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