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
423 static const uintmax_t power10[] = {
424
425 1ULL,
426 10ULL,
427 100ULL,
428 1000ULL,
429 10000ULL,
430 100000ULL,
431 1000000ULL,
432 10000000ULL,
433 100000000ULL,
434 1000000000ULL
435
436
437
438 #if SIZEOF_UINTMAX_T == 8
439 ,
440 10000000000ULL,
441 100000000000ULL,
442 1000000000000ULL,
443 10000000000000ULL,
444 100000000000000ULL,
445 1000000000000000ULL,
446 10000000000000000ULL,
447 100000000000000000ULL,
448 1000000000000000000ULL,
449 10000000000000000000ULL
450
451
452
453 #endif
454 };
455
456 static const char *const suffix[] =
457 { "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", NULL };
458 static const char *const suffix_lc[] =
459 { "", "k", "m", "g", "t", "p", "e", "z", "y", "r", "q", NULL };
460
461
462 const char *const *sfx = use_si ? suffix_lc : suffix;
463 int j = 0;
464
465 if (len == 0)
466 len = 9;
467 #if SIZEOF_UINTMAX_T == 8
468
469 else if (len > 19)
470 len = 19;
471 #else
472
473 else if (len > 9)
474 len = 9;
475 #endif
476
477
478
479
480
481
482 if (use_si)
483 for (j = 0; j < units; j++)
484 {
485 uintmax_t size_remain;
486
487 size_remain = ((size % 125) * 1024) / 1000;
488 size /= 125;
489 size *= 128;
490 size += size_remain;
491 }
492
493 for (j = units; sfx[j] != NULL; j++)
494 {
495 if (size == 0)
496 {
497 if (j == units)
498 {
499
500 g_snprintf (buffer, len + 1, "%s", "0");
501 }
502 else
503 {
504
505 g_snprintf (buffer, len + 1, (len > 1) ? "~%s" : "%s", (j > 1) ? sfx[j - 1] : "B");
506 }
507 break;
508 }
509
510 if (size < power10[len - (j > 0 ? 1 : 0)])
511 {
512 g_snprintf (buffer, len + 1, "%" PRIuMAX "%s", size, sfx[j]);
513 break;
514 }
515
516
517 if (use_si)
518 size = (size + 500) / 1000;
519 else
520 size = (size + 512) >> 10;
521 }
522 }
523
524
525
526 const char *
527 string_perm (mode_t mode_bits)
528 {
529 static char mode[11];
530
531 strcpy (mode, "----------");
532 if (S_ISDIR (mode_bits))
533 mode[0] = 'd';
534 if (S_ISCHR (mode_bits))
535 mode[0] = 'c';
536 if (S_ISBLK (mode_bits))
537 mode[0] = 'b';
538 if (S_ISLNK (mode_bits))
539 mode[0] = 'l';
540 if (S_ISFIFO (mode_bits))
541 mode[0] = 'p';
542 if (S_ISNAM (mode_bits))
543 mode[0] = 'n';
544 if (S_ISSOCK (mode_bits))
545 mode[0] = 's';
546 if (S_ISDOOR (mode_bits))
547 mode[0] = 'D';
548 if (ismode (mode_bits, S_IXOTH))
549 mode[9] = 'x';
550 if (ismode (mode_bits, S_IWOTH))
551 mode[8] = 'w';
552 if (ismode (mode_bits, S_IROTH))
553 mode[7] = 'r';
554 if (ismode (mode_bits, S_IXGRP))
555 mode[6] = 'x';
556 if (ismode (mode_bits, S_IWGRP))
557 mode[5] = 'w';
558 if (ismode (mode_bits, S_IRGRP))
559 mode[4] = 'r';
560 if (ismode (mode_bits, S_IXUSR))
561 mode[3] = 'x';
562 if (ismode (mode_bits, S_IWUSR))
563 mode[2] = 'w';
564 if (ismode (mode_bits, S_IRUSR))
565 mode[1] = 'r';
566 #ifdef S_ISUID
567 if (ismode (mode_bits, S_ISUID))
568 mode[3] = (mode[3] == 'x') ? 's' : 'S';
569 #endif
570 #ifdef S_ISGID
571 if (ismode (mode_bits, S_ISGID))
572 mode[6] = (mode[6] == 'x') ? 's' : 'S';
573 #endif
574 #ifdef S_ISVTX
575 if (ismode (mode_bits, S_ISVTX))
576 mode[9] = (mode[9] == 'x') ? 't' : 'T';
577 #endif
578 return mode;
579 }
580
581
582
583 const char *
584 extension (const char *filename)
585 {
586 const char *d;
587
588 d = strrchr (filename, '.');
589
590 return d != NULL ? d + 1 : "";
591 }
592
593
594
595 char *
596 load_mc_home_file (const char *from, const char *filename, char **allocated_filename,
597 size_t *length)
598 {
599 char *hintfile_base, *hintfile;
600 char *lang;
601 char *data;
602
603 hintfile_base = g_build_filename (from, filename, (char *) NULL);
604 lang = guess_message_value ();
605
606 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
607 if (!g_file_get_contents (hintfile, &data, length, NULL))
608 {
609
610 if (lang[0] != '\0' && lang[1] != '\0')
611 lang[2] = '\0';
612 g_free (hintfile);
613 hintfile = g_strconcat (hintfile_base, ".", lang, (char *) NULL);
614 if (!g_file_get_contents (hintfile, &data, length, NULL))
615 {
616 g_free (hintfile);
617 hintfile = hintfile_base;
618 g_file_get_contents (hintfile_base, &data, length, NULL);
619 }
620 }
621
622 g_free (lang);
623
624 if (hintfile != hintfile_base)
625 g_free (hintfile_base);
626
627 if (allocated_filename != NULL)
628 *allocated_filename = hintfile;
629 else
630 g_free (hintfile);
631
632 return data;
633 }
634
635
636
637 const char *
638 extract_line (const char *s, const char *top, size_t *len)
639 {
640 static char tmp_line[BUF_MEDIUM];
641 char *t = tmp_line;
642
643 while (*s != '\0' && *s != '\n' && (size_t) (t - tmp_line) < sizeof (tmp_line) - 1 && s < top)
644 *t++ = *s++;
645 *t = '\0';
646
647 if (len != NULL)
648 *len = (size_t) (t - tmp_line);
649
650 return tmp_line;
651 }
652
653
654
655
656
657
658 const char *
659 x_basename (const char *s)
660 {
661 const char *url_delim, *path_sep;
662
663 url_delim = g_strrstr (s, VFS_PATH_URL_DELIMITER);
664 path_sep = strrchr (s, PATH_SEP);
665
666 if (path_sep == NULL)
667 return s;
668
669 if (url_delim == NULL
670 || url_delim < path_sep - strlen (VFS_PATH_URL_DELIMITER)
671 || url_delim - s + strlen (VFS_PATH_URL_DELIMITER) < strlen (s))
672 {
673
674 if (!IS_PATH_SEP (s[strlen (s) - 1]))
675 return path_sep + 1;
676
677 while (--path_sep > s && !IS_PATH_SEP (*path_sep))
678 ;
679 return (path_sep != s) ? path_sep + 1 : s;
680 }
681
682 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
683 ;
684 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
685 ;
686
687 return url_delim == s ? s : url_delim + 1;
688 }
689
690
691
692 const char *
693 unix_error_string (int error_num)
694 {
695 static char buffer[BUF_LARGE];
696 gchar *strerror_currentlocale;
697
698 strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
699 g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
700 g_free (strerror_currentlocale);
701
702 return buffer;
703 }
704
705
706
707 const char *
708 skip_separators (const char *s)
709 {
710 const char *su = s;
711
712 for (; *su != '\0'; str_cnext_char (&su))
713 if (!whitespace (*su) && *su != ',')
714 break;
715
716 return su;
717 }
718
719
720
721 const char *
722 skip_numbers (const char *s)
723 {
724 const char *su = s;
725
726 for (; *su != '\0'; str_cnext_char (&su))
727 if (!str_isdigit (su))
728 break;
729
730 return su;
731 }
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751 char *
752 strip_ctrl_codes (char *s)
753 {
754 char *w;
755 char *r;
756
757 if (s == NULL)
758 return NULL;
759
760 for (w = s, r = s; *r != '\0';)
761 {
762 if (*r == ESC_CHAR)
763 {
764 ;
765
766 if (*(++r) == '[' || *r == '(')
767 {
768
769 while (*(++r) != '\0' && strchr ("0123456789;:<=>?", *r) != NULL)
770 ;
771 while (*r != '\0' && (*r < 0x40 || *r > 0x7E))
772 ++r;
773 }
774 else if (*r == ']')
775 {
776
777
778
779
780
781
782 char *new_r;
783
784 for (new_r = r; *new_r != '\0'; new_r++)
785 {
786 switch (*new_r)
787 {
788
789 case '\a':
790 r = new_r;
791 goto osc_out;
792 case ESC_CHAR:
793
794 if (new_r[1] == '\\')
795 {
796 r = new_r + 1;
797 goto osc_out;
798 }
799 break;
800 default:
801 break;
802 }
803 }
804 osc_out:
805 ;
806 }
807
808
809
810
811
812 if (*r != '\0')
813 r++;
814 }
815 else
816 {
817 char *n;
818
819 n = str_get_next_char (r);
820 if (str_isprint (r))
821 {
822 memmove (w, r, n - r);
823 w += n - r;
824 }
825 r = n;
826 }
827 }
828
829 *w = '\0';
830 return s;
831 }
832
833
834
835 enum compression_type
836 get_compression_type (int fd, const char *name)
837 {
838 unsigned char magic[16];
839 size_t str_len;
840
841
842 if (mc_read (fd, (char *) magic, 4) != 4)
843 return COMPRESSION_NONE;
844
845
846 if (magic[0] == 0x1F && (magic[1] == 0x8B || magic[1] == 0x9E))
847 return COMPRESSION_GZIP;
848
849
850 if (magic[0] == 'P' && magic[1] == 'K' && magic[2] == 0x03 && magic[3] == 0x04)
851 {
852
853 mc_lseek (fd, 8, SEEK_SET);
854 if (mc_read (fd, (char *) magic, 2) != 2)
855 return COMPRESSION_NONE;
856
857 if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
858 return COMPRESSION_NONE;
859
860 return COMPRESSION_ZIP;
861 }
862
863
864 if (magic[0] == 0x1F && (magic[1] == 0x1E || magic[1] == 0xA0 || magic[1] == 0x9D))
865
866 return COMPRESSION_GZIP;
867
868
869 if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
870 switch (magic[2])
871 {
872 case '0':
873 return COMPRESSION_BZIP;
874 case 'h':
875 return COMPRESSION_BZIP2;
876 default:
877 break;
878 }
879
880
881 if (magic[0] == 0x04 && magic[1] == 0x22 && magic[2] == 0x4d && magic[3] == 0x18)
882 return COMPRESSION_LZ4;
883
884 if (mc_read (fd, (char *) magic + 4, 2) != 2)
885 return COMPRESSION_NONE;
886
887
888 if (magic[0] == 'L'
889 && magic[1] == 'Z'
890 && magic[2] == 'I' && magic[3] == 'P' && (magic[4] == 0x00 || magic[4] == 0x01))
891 return COMPRESSION_LZIP;
892
893
894
895 if (magic[0] == 0xFF
896 && magic[1] == 'L'
897 && magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A' && magic[5] == 0x00)
898 return COMPRESSION_LZMA;
899
900
901 if (magic[0] == 0x89 && magic[1] == 0x4c &&
902 magic[2] == 0x5a && magic[3] == 0x4f && magic[4] == 0x00 && magic[5] == 0x0d)
903 return COMPRESSION_LZO;
904
905
906 if (magic[0] == 0xFD
907 && magic[1] == 0x37
908 && magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
909 return COMPRESSION_XZ;
910
911 if (magic[0] == 0x28 && magic[1] == 0xB5 && magic[2] == 0x2F && magic[3] == 0xFD)
912 return COMPRESSION_ZSTD;
913
914 str_len = strlen (name);
915
916 if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0) ||
917 (str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
918 return COMPRESSION_LZMA;
919
920 return COMPRESSION_NONE;
921 }
922
923
924
925 const char *
926 decompress_extension (int type)
927 {
928 switch (type)
929 {
930 case COMPRESSION_ZIP:
931 return "/uz" VFS_PATH_URL_DELIMITER;
932 case COMPRESSION_GZIP:
933 return "/ugz" VFS_PATH_URL_DELIMITER;
934 case COMPRESSION_BZIP:
935 return "/ubz" VFS_PATH_URL_DELIMITER;
936 case COMPRESSION_BZIP2:
937 return "/ubz2" VFS_PATH_URL_DELIMITER;
938 case COMPRESSION_LZIP:
939 return "/ulz" VFS_PATH_URL_DELIMITER;
940 case COMPRESSION_LZ4:
941 return "/ulz4" VFS_PATH_URL_DELIMITER;
942 case COMPRESSION_LZMA:
943 return "/ulzma" VFS_PATH_URL_DELIMITER;
944 case COMPRESSION_LZO:
945 return "/ulzo" VFS_PATH_URL_DELIMITER;
946 case COMPRESSION_XZ:
947 return "/uxz" VFS_PATH_URL_DELIMITER;
948 case COMPRESSION_ZSTD:
949 return "/uzst" VFS_PATH_URL_DELIMITER;
950 default:
951 break;
952 }
953
954 fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
955 return 0;
956 }
957
958
959
960 void
961 wipe_password (char *passwd)
962 {
963 if (passwd != NULL)
964 {
965 char *p;
966
967 for (p = passwd; *p != '\0'; p++)
968 *p = '\0';
969 g_free (passwd);
970 }
971 }
972
973
974
975
976
977
978
979
980
981
982 char *
983 convert_controls (const char *p)
984 {
985 char *valcopy;
986 char *q;
987
988 valcopy = g_strdup (p);
989
990
991 for (q = valcopy; *p != '\0';)
992 switch (*p)
993 {
994 case '\\':
995 p++;
996
997 if (*p == 'e' || *p == 'E')
998 {
999 p++;
1000 *q++ = ESC_CHAR;
1001 }
1002 break;
1003
1004 case '^':
1005 p++;
1006 if (*p == '^')
1007 *q++ = *p++;
1008 else
1009 {
1010 char c;
1011
1012 c = *p | 0x20;
1013 if (c >= 'a' && c <= 'z')
1014 {
1015 *q++ = c - 'a' + 1;
1016 p++;
1017 }
1018 else if (*p != '\0')
1019 p++;
1020 }
1021 break;
1022
1023 default:
1024 *q++ = *p++;
1025 }
1026
1027 *q = '\0';
1028 return valcopy;
1029 }
1030
1031
1032
1033
1034
1035
1036
1037 char *
1038 diff_two_paths (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
1039 {
1040 int j, prevlen = -1, currlen;
1041 char *my_first = NULL, *my_second = NULL;
1042 char *buf = NULL;
1043
1044 my_first = resolve_symlinks (vpath1);
1045 if (my_first == NULL)
1046 goto ret;
1047
1048 my_second = resolve_symlinks (vpath2);
1049 if (my_second == NULL)
1050 goto ret;
1051
1052 for (j = 0; j < 2; j++)
1053 {
1054 char *p, *q;
1055 int i;
1056
1057 p = my_first;
1058 q = my_second;
1059
1060 while (TRUE)
1061 {
1062 char *r, *s;
1063 ptrdiff_t len;
1064
1065 r = strchr (p, PATH_SEP);
1066 if (r == NULL)
1067 break;
1068 s = strchr (q, PATH_SEP);
1069 if (s == NULL)
1070 break;
1071
1072 len = r - p;
1073 if (len != (s - q) || strncmp (p, q, (size_t) len) != 0)
1074 break;
1075
1076 p = r + 1;
1077 q = s + 1;
1078 }
1079 p--;
1080 for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++)
1081 ;
1082 currlen = (i + 1) * 3 + strlen (q) + 1;
1083 if (j != 0)
1084 {
1085 if (currlen < prevlen)
1086 g_free (buf);
1087 else
1088 goto ret;
1089 }
1090 p = buf = g_malloc (currlen);
1091 prevlen = currlen;
1092 for (; i >= 0; i--, p += 3)
1093 strcpy (p, "../");
1094 strcpy (p, q);
1095 }
1096
1097 ret:
1098 g_free (my_first);
1099 g_free (my_second);
1100 return buf;
1101 }
1102
1103
1104
1105
1106
1107
1108 GList *
1109 list_append_unique (GList *list, char *text)
1110 {
1111 GList *lc_link;
1112
1113
1114
1115
1116
1117
1118 list = g_list_append (list, text);
1119 list = g_list_last (list);
1120 lc_link = g_list_previous (list);
1121
1122 while (lc_link != NULL)
1123 {
1124 GList *newlink;
1125
1126 newlink = g_list_previous (lc_link);
1127 if (strcmp ((char *) lc_link->data, text) == 0)
1128 {
1129 GList *tmp;
1130
1131 g_free (lc_link->data);
1132 tmp = g_list_remove_link (list, lc_link);
1133 (void) tmp;
1134 g_list_free_1 (lc_link);
1135 }
1136 lc_link = newlink;
1137 }
1138
1139 return list;
1140 }
1141
1142
1143
1144
1145
1146
1147
1148 void
1149 load_file_position (const vfs_path_t *filename_vpath, long *line, long *column, off_t *offset,
1150 GArray **bookmarks)
1151 {
1152 char *fn;
1153 FILE *f;
1154 char buf[MC_MAXPATHLEN + 100];
1155 const size_t len = vfs_path_len (filename_vpath);
1156
1157
1158 *line = 1;
1159 *column = 0;
1160 *offset = 0;
1161
1162
1163 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1164 f = fopen (fn, "r");
1165 g_free (fn);
1166 if (f == NULL)
1167 return;
1168
1169
1170 if (bookmarks != NULL)
1171 *bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
1172
1173 while (fgets (buf, sizeof (buf), f) != NULL)
1174 {
1175 const char *p;
1176 gchar **pos_tokens;
1177
1178
1179 if (strncmp (buf, vfs_path_as_str (filename_vpath), len) != 0)
1180 continue;
1181
1182
1183 if (buf[len] != ' ')
1184 continue;
1185
1186
1187 p = &buf[len + 1];
1188 if (strchr (p, ' ') != NULL)
1189 continue;
1190
1191 pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
1192 if (pos_tokens[0] == NULL)
1193 {
1194 *line = 1;
1195 *column = 0;
1196 *offset = 0;
1197 }
1198 else
1199 {
1200 *line = strtol (pos_tokens[0], NULL, 10);
1201 if (pos_tokens[1] == NULL)
1202 {
1203 *column = 0;
1204 *offset = 0;
1205 }
1206 else
1207 {
1208 *column = strtol (pos_tokens[1], NULL, 10);
1209 if (pos_tokens[2] == NULL)
1210 *offset = 0;
1211 else if (bookmarks != NULL)
1212 {
1213 size_t i;
1214
1215 *offset = (off_t) g_ascii_strtoll (pos_tokens[2], NULL, 10);
1216
1217 for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
1218 {
1219 size_t val;
1220
1221 val = strtoul (pos_tokens[3 + i], NULL, 10);
1222 g_array_append_val (*bookmarks, val);
1223 }
1224 }
1225 }
1226 }
1227
1228 g_strfreev (pos_tokens);
1229 }
1230
1231 fclose (f);
1232 }
1233
1234
1235
1236
1237
1238
1239 void
1240 save_file_position (const vfs_path_t *filename_vpath, long line, long column, off_t offset,
1241 GArray *bookmarks)
1242 {
1243 static size_t filepos_max_saved_entries = 0;
1244 char *fn, *tmp_fn;
1245 FILE *f, *tmp_f;
1246 char buf[MC_MAXPATHLEN + 100];
1247 size_t i;
1248 const size_t len = vfs_path_len (filename_vpath);
1249 gboolean src_error = FALSE;
1250
1251 if (filepos_max_saved_entries == 0)
1252 filepos_max_saved_entries = mc_config_get_int (mc_global.main_config, CONFIG_APP_SECTION,
1253 "filepos_max_saved_entries", 1024);
1254
1255 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1256 if (fn == NULL)
1257 goto early_error;
1258
1259 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
1260
1261
1262 f = fopen (fn, "w");
1263 if (f == NULL)
1264 goto open_target_error;
1265
1266 tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
1267 tmp_f = fopen (tmp_fn, "r");
1268 if (tmp_f == NULL)
1269 {
1270 src_error = TRUE;
1271 goto open_source_error;
1272 }
1273
1274
1275 if (line != 1 || column != 0 || bookmarks != NULL)
1276 {
1277 if (fprintf
1278 (f, "%s %ld;%ld;%" PRIuMAX, vfs_path_as_str (filename_vpath), line, column,
1279 (uintmax_t) offset) < 0)
1280 goto write_position_error;
1281 if (bookmarks != NULL)
1282 for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
1283 if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
1284 goto write_position_error;
1285
1286 if (fprintf (f, "\n") < 0)
1287 goto write_position_error;
1288 }
1289
1290 i = 1;
1291 while (fgets (buf, sizeof (buf), tmp_f) != NULL)
1292 {
1293 if (buf[len] == ' ' && strncmp (buf, vfs_path_as_str (filename_vpath), len) == 0
1294 && strchr (&buf[len + 1], ' ') == NULL)
1295 continue;
1296
1297 fprintf (f, "%s", buf);
1298 if (++i > filepos_max_saved_entries)
1299 break;
1300 }
1301
1302 write_position_error:
1303 fclose (tmp_f);
1304 open_source_error:
1305 g_free (tmp_fn);
1306 fclose (f);
1307 if (src_error)
1308 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
1309 else
1310 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
1311 open_target_error:
1312 g_free (fn);
1313 early_error:
1314 if (bookmarks != NULL)
1315 g_array_free (bookmarks, TRUE);
1316 }
1317
1318
1319
1320 extern int
1321 ascii_alpha_to_cntrl (int ch)
1322 {
1323 if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
1324 ch &= 0x1f;
1325
1326 return ch;
1327 }
1328
1329
1330
1331 const char *
1332 Q_ (const char *s)
1333 {
1334 const char *result, *sep;
1335
1336 result = _(s);
1337 sep = strchr (result, '|');
1338
1339 return sep != NULL ? sep + 1 : result;
1340 }
1341
1342
1343
1344 gboolean
1345 mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
1346 {
1347 struct stat stat_buf;
1348 char *backup_path;
1349 gboolean ret;
1350
1351 if (!exist_file (file_name))
1352 return FALSE;
1353
1354 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1355 if (backup_path == NULL)
1356 return FALSE;
1357
1358 ret = mc_util_write_backup_content (file_name, backup_path);
1359 if (ret)
1360 {
1361
1362 if (stat (file_name, &stat_buf) == 0)
1363 chmod (backup_path, stat_buf.st_mode);
1364 else
1365 chmod (backup_path, S_IRUSR | S_IWUSR);
1366 }
1367
1368 g_free (backup_path);
1369
1370 return ret;
1371 }
1372
1373
1374
1375 gboolean
1376 mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
1377 {
1378 gboolean ret;
1379 char *backup_path;
1380
1381 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1382 if (backup_path == NULL)
1383 return FALSE;
1384
1385 ret = mc_util_write_backup_content (backup_path, file_name);
1386 g_free (backup_path);
1387
1388 return ret;
1389 }
1390
1391
1392
1393 gboolean
1394 mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
1395 {
1396 char *backup_path;
1397
1398 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1399 if (backup_path == NULL)
1400 return FALSE;
1401
1402 if (exist_file (backup_path))
1403 {
1404 vfs_path_t *vpath;
1405
1406 vpath = vfs_path_from_str (backup_path);
1407 mc_unlink (vpath);
1408 vfs_path_free (vpath, TRUE);
1409 }
1410
1411 g_free (backup_path);
1412 return TRUE;
1413 }
1414
1415
1416
1417
1418
1419
1420
1421 char *
1422 guess_message_value (void)
1423 {
1424 static const char *const var[] = {
1425
1426
1427 "LC_ALL",
1428
1429 "LC_MESSAGES",
1430
1431 "LANG",
1432
1433 NULL
1434 };
1435
1436 size_t i;
1437 const char *locale = NULL;
1438
1439 for (i = 0; var[i] != NULL; i++)
1440 {
1441 locale = getenv (var[i]);
1442 if (locale != NULL && locale[0] != '\0')
1443 break;
1444 }
1445
1446 if (locale == NULL)
1447 locale = "";
1448
1449 return g_strdup (locale);
1450 }
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 const char *
1462 mc_get_profile_root (void)
1463 {
1464 static const char *profile_root = NULL;
1465
1466 if (profile_root == NULL)
1467 {
1468 profile_root = g_getenv ("MC_PROFILE_ROOT");
1469 if (profile_root == NULL || *profile_root == '\0')
1470 profile_root = mc_config_get_home_dir ();
1471 }
1472
1473 return profile_root;
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486 void
1487 mc_propagate_error (GError **dest, int code, const char *format, ...)
1488 {
1489 if (dest != NULL && *dest == NULL)
1490 {
1491 GError *tmp_error;
1492 va_list args;
1493
1494 va_start (args, format);
1495 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1496 va_end (args);
1497
1498 g_propagate_error (dest, tmp_error);
1499 }
1500 }
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512 void
1513 mc_replace_error (GError **dest, int code, const char *format, ...)
1514 {
1515 if (dest != NULL)
1516 {
1517 GError *tmp_error;
1518 va_list args;
1519
1520 va_start (args, format);
1521 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1522 va_end (args);
1523
1524 g_error_free (*dest);
1525 *dest = NULL;
1526 g_propagate_error (dest, tmp_error);
1527 }
1528 }
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541 gboolean
1542 mc_time_elapsed (gint64 *timestamp, gint64 delay)
1543 {
1544 gint64 now;
1545
1546 now = g_get_monotonic_time ();
1547
1548 if (now >= *timestamp && now < *timestamp + delay)
1549 return FALSE;
1550
1551 *timestamp = now;
1552 return TRUE;
1553 }
1554
1555