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 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
682 || url_delim < path_sep - strlen (VFS_PATH_URL_DELIMITER)
683 || url_delim - s + strlen (VFS_PATH_URL_DELIMITER) < strlen (s))
684 {
685
686 if (!IS_PATH_SEP (s[strlen (s) - 1]))
687 return path_sep + 1;
688
689 while (--path_sep > s && !IS_PATH_SEP (*path_sep))
690 ;
691 return (path_sep != s) ? path_sep + 1 : s;
692 }
693
694 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
695 ;
696 while (--url_delim > s && !IS_PATH_SEP (*url_delim))
697 ;
698
699 return url_delim == s ? s : url_delim + 1;
700 }
701
702
703
704 const char *
705 unix_error_string (int error_num)
706 {
707 static char buffer[BUF_LARGE];
708 gchar *strerror_currentlocale;
709
710 strerror_currentlocale = g_locale_from_utf8 (g_strerror (error_num), -1, NULL, NULL, NULL);
711 g_snprintf (buffer, sizeof (buffer), "%s (%d)", strerror_currentlocale, error_num);
712 g_free (strerror_currentlocale);
713
714 return buffer;
715 }
716
717
718
719 const char *
720 skip_separators (const char *s)
721 {
722 const char *su = s;
723
724 for (; *su != '\0'; str_cnext_char (&su))
725 if (!whitespace (*su) && *su != ',')
726 break;
727
728 return su;
729 }
730
731
732
733 const char *
734 skip_numbers (const char *s)
735 {
736 const char *su = s;
737
738 for (; *su != '\0'; str_cnext_char (&su))
739 if (!str_isdigit (su))
740 break;
741
742 return su;
743 }
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763 char *
764 strip_ctrl_codes (char *s)
765 {
766 char *w;
767 char *r;
768
769 if (s == NULL)
770 return NULL;
771
772 for (w = s, r = s; *r != '\0';)
773 {
774 if (*r == ESC_CHAR)
775 {
776 ;
777
778 if (*(++r) == '[' || *r == '(')
779 {
780
781 while (*(++r) != '\0' && strchr ("0123456789;:<=>?", *r) != NULL)
782 ;
783 while (*r != '\0' && (*r < 0x40 || *r > 0x7E))
784 ++r;
785 }
786 else if (*r == ']')
787 {
788
789
790
791
792
793
794 char *new_r;
795
796 for (new_r = r; *new_r != '\0'; new_r++)
797 {
798 switch (*new_r)
799 {
800
801 case '\a':
802 r = new_r;
803 goto osc_out;
804 case ESC_CHAR:
805
806 if (new_r[1] == '\\')
807 {
808 r = new_r + 1;
809 goto osc_out;
810 }
811 break;
812 default:
813 break;
814 }
815 }
816 osc_out:
817 ;
818 }
819
820
821
822
823
824 if (*r != '\0')
825 r++;
826 }
827 else
828 {
829 char *n;
830
831 n = str_get_next_char (r);
832 if (str_isprint (r))
833 {
834 memmove (w, r, n - r);
835 w += n - r;
836 }
837 r = n;
838 }
839 }
840
841 *w = '\0';
842 return s;
843 }
844
845
846
847 enum compression_type
848 get_compression_type (int fd, const char *name)
849 {
850 unsigned char magic[16];
851 size_t str_len;
852
853
854 if (mc_read (fd, (char *) magic, 4) != 4)
855 return COMPRESSION_NONE;
856
857
858 if (magic[0] == 0x1F && (magic[1] == 0x8B || magic[1] == 0x9E))
859 return COMPRESSION_GZIP;
860
861
862 if (magic[0] == 'P' && magic[1] == 'K' && magic[2] == 0x03 && magic[3] == 0x04)
863 {
864
865 mc_lseek (fd, 8, SEEK_SET);
866 if (mc_read (fd, (char *) magic, 2) != 2)
867 return COMPRESSION_NONE;
868
869 if ((magic[0] != 8 && magic[0] != 0) || magic[1] != 0)
870 return COMPRESSION_NONE;
871
872 return COMPRESSION_ZIP;
873 }
874
875
876 if (magic[0] == 0x1F && (magic[1] == 0x1E || magic[1] == 0xA0 || magic[1] == 0x9D))
877
878 return COMPRESSION_GZIP;
879
880
881 if ((magic[0] == 'B') && (magic[1] == 'Z') && (magic[3] >= '1') && (magic[3] <= '9'))
882 switch (magic[2])
883 {
884 case '0':
885 return COMPRESSION_BZIP;
886 case 'h':
887 return COMPRESSION_BZIP2;
888 default:
889 break;
890 }
891
892
893 if (magic[0] == 0x04 && magic[1] == 0x22 && magic[2] == 0x4d && magic[3] == 0x18)
894 return COMPRESSION_LZ4;
895
896 if (mc_read (fd, (char *) magic + 4, 2) != 2)
897 return COMPRESSION_NONE;
898
899
900 if (magic[0] == 'L'
901 && magic[1] == 'Z'
902 && magic[2] == 'I' && magic[3] == 'P' && (magic[4] == 0x00 || magic[4] == 0x01))
903 return COMPRESSION_LZIP;
904
905
906
907 if (magic[0] == 0xFF
908 && magic[1] == 'L'
909 && magic[2] == 'Z' && magic[3] == 'M' && magic[4] == 'A' && magic[5] == 0x00)
910 return COMPRESSION_LZMA;
911
912
913 if (magic[0] == 0x89 && magic[1] == 0x4c &&
914 magic[2] == 0x5a && magic[3] == 0x4f && magic[4] == 0x00 && magic[5] == 0x0d)
915 return COMPRESSION_LZO;
916
917
918 if (magic[0] == 0xFD
919 && magic[1] == 0x37
920 && magic[2] == 0x7A && magic[3] == 0x58 && magic[4] == 0x5A && magic[5] == 0x00)
921 return COMPRESSION_XZ;
922
923 if (magic[0] == 0x28 && magic[1] == 0xB5 && magic[2] == 0x2F && magic[3] == 0xFD)
924 return COMPRESSION_ZSTD;
925
926 str_len = strlen (name);
927
928 if ((str_len > 5 && strcmp (&name[str_len - 5], ".lzma") == 0) ||
929 (str_len > 4 && strcmp (&name[str_len - 4], ".tlz") == 0))
930 return COMPRESSION_LZMA;
931
932 return COMPRESSION_NONE;
933 }
934
935
936
937 const char *
938 decompress_extension (int type)
939 {
940 switch (type)
941 {
942 case COMPRESSION_ZIP:
943 return "/uz" VFS_PATH_URL_DELIMITER;
944 case COMPRESSION_GZIP:
945 return "/ugz" VFS_PATH_URL_DELIMITER;
946 case COMPRESSION_BZIP:
947 return "/ubz" VFS_PATH_URL_DELIMITER;
948 case COMPRESSION_BZIP2:
949 return "/ubz2" VFS_PATH_URL_DELIMITER;
950 case COMPRESSION_LZIP:
951 return "/ulz" VFS_PATH_URL_DELIMITER;
952 case COMPRESSION_LZ4:
953 return "/ulz4" VFS_PATH_URL_DELIMITER;
954 case COMPRESSION_LZMA:
955 return "/ulzma" VFS_PATH_URL_DELIMITER;
956 case COMPRESSION_LZO:
957 return "/ulzo" VFS_PATH_URL_DELIMITER;
958 case COMPRESSION_XZ:
959 return "/uxz" VFS_PATH_URL_DELIMITER;
960 case COMPRESSION_ZSTD:
961 return "/uzst" VFS_PATH_URL_DELIMITER;
962 default:
963 break;
964 }
965
966 fprintf (stderr, "Fatal: decompress_extension called with an unknown argument\n");
967 return 0;
968 }
969
970
971
972 void
973 wipe_password (char *passwd)
974 {
975 if (passwd != NULL)
976 {
977 char *p;
978
979 for (p = passwd; *p != '\0'; p++)
980 *p = '\0';
981 g_free (passwd);
982 }
983 }
984
985
986
987
988
989
990
991
992
993
994 char *
995 convert_controls (const char *p)
996 {
997 char *valcopy;
998 char *q;
999
1000 valcopy = g_strdup (p);
1001
1002
1003 for (q = valcopy; *p != '\0';)
1004 switch (*p)
1005 {
1006 case '\\':
1007 p++;
1008
1009 if (*p == 'e' || *p == 'E')
1010 {
1011 p++;
1012 *q++ = ESC_CHAR;
1013 }
1014 break;
1015
1016 case '^':
1017 p++;
1018 if (*p == '^')
1019 *q++ = *p++;
1020 else
1021 {
1022 char c;
1023
1024 c = *p | 0x20;
1025 if (c >= 'a' && c <= 'z')
1026 {
1027 *q++ = c - 'a' + 1;
1028 p++;
1029 }
1030 else if (*p != '\0')
1031 p++;
1032 }
1033 break;
1034
1035 default:
1036 *q++ = *p++;
1037 }
1038
1039 *q = '\0';
1040 return valcopy;
1041 }
1042
1043
1044
1045
1046
1047
1048
1049 char *
1050 diff_two_paths (const vfs_path_t *vpath1, const vfs_path_t *vpath2)
1051 {
1052 int j, prevlen = -1, currlen;
1053 char *my_first = NULL, *my_second = NULL;
1054 char *buf = NULL;
1055
1056 my_first = resolve_symlinks (vpath1);
1057 if (my_first == NULL)
1058 goto ret;
1059
1060 my_second = resolve_symlinks (vpath2);
1061 if (my_second == NULL)
1062 goto ret;
1063
1064 for (j = 0; j < 2; j++)
1065 {
1066 char *p, *q;
1067 int i;
1068
1069 p = my_first;
1070 q = my_second;
1071
1072 while (TRUE)
1073 {
1074 char *r, *s;
1075 ptrdiff_t len;
1076
1077 r = strchr (p, PATH_SEP);
1078 if (r == NULL)
1079 break;
1080 s = strchr (q, PATH_SEP);
1081 if (s == NULL)
1082 break;
1083
1084 len = r - p;
1085 if (len != (s - q) || strncmp (p, q, (size_t) len) != 0)
1086 break;
1087
1088 p = r + 1;
1089 q = s + 1;
1090 }
1091 p--;
1092 for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++)
1093 ;
1094 currlen = (i + 1) * 3 + strlen (q) + 1;
1095 if (j != 0)
1096 {
1097 if (currlen < prevlen)
1098 g_free (buf);
1099 else
1100 goto ret;
1101 }
1102 p = buf = g_malloc (currlen);
1103 prevlen = currlen;
1104 for (; i >= 0; i--, p += 3)
1105 strcpy (p, "../");
1106 strcpy (p, q);
1107 }
1108
1109 ret:
1110 g_free (my_first);
1111 g_free (my_second);
1112 return buf;
1113 }
1114
1115
1116
1117
1118
1119
1120 GList *
1121 list_append_unique (GList *list, char *text)
1122 {
1123 GList *lc_link;
1124
1125
1126
1127
1128
1129
1130 list = g_list_append (list, text);
1131 list = g_list_last (list);
1132 lc_link = g_list_previous (list);
1133
1134 while (lc_link != NULL)
1135 {
1136 GList *newlink;
1137
1138 newlink = g_list_previous (lc_link);
1139 if (strcmp ((char *) lc_link->data, text) == 0)
1140 {
1141 GList *tmp;
1142
1143 g_free (lc_link->data);
1144 tmp = g_list_remove_link (list, lc_link);
1145 (void) tmp;
1146 g_list_free_1 (lc_link);
1147 }
1148 lc_link = newlink;
1149 }
1150
1151 return list;
1152 }
1153
1154
1155
1156
1157
1158
1159
1160 void
1161 load_file_position (const vfs_path_t *filename_vpath, long *line, long *column, off_t *offset,
1162 GArray **bookmarks)
1163 {
1164 char *fn;
1165 FILE *f;
1166 char buf[MC_MAXPATHLEN + 100];
1167 const size_t len = vfs_path_len (filename_vpath);
1168
1169
1170 *line = 1;
1171 *column = 0;
1172 *offset = 0;
1173
1174
1175 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1176 f = fopen (fn, "r");
1177 g_free (fn);
1178 if (f == NULL)
1179 return;
1180
1181
1182 if (bookmarks != NULL)
1183 *bookmarks = g_array_sized_new (FALSE, FALSE, sizeof (size_t), MAX_SAVED_BOOKMARKS);
1184
1185 while (fgets (buf, sizeof (buf), f) != NULL)
1186 {
1187 const char *p;
1188 gchar **pos_tokens;
1189
1190
1191 if (strncmp (buf, vfs_path_as_str (filename_vpath), len) != 0)
1192 continue;
1193
1194
1195 if (buf[len] != ' ')
1196 continue;
1197
1198
1199 p = &buf[len + 1];
1200 if (strchr (p, ' ') != NULL)
1201 continue;
1202
1203 pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
1204 if (pos_tokens[0] == NULL)
1205 {
1206 *line = 1;
1207 *column = 0;
1208 *offset = 0;
1209 }
1210 else
1211 {
1212 *line = strtol (pos_tokens[0], NULL, 10);
1213 if (pos_tokens[1] == NULL)
1214 {
1215 *column = 0;
1216 *offset = 0;
1217 }
1218 else
1219 {
1220 *column = strtol (pos_tokens[1], NULL, 10);
1221 if (pos_tokens[2] == NULL)
1222 *offset = 0;
1223 else if (bookmarks != NULL)
1224 {
1225 size_t i;
1226
1227 *offset = (off_t) g_ascii_strtoll (pos_tokens[2], NULL, 10);
1228
1229 for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
1230 {
1231 size_t val;
1232
1233 val = strtoul (pos_tokens[3 + i], NULL, 10);
1234 g_array_append_val (*bookmarks, val);
1235 }
1236 }
1237 }
1238 }
1239
1240 g_strfreev (pos_tokens);
1241 }
1242
1243 fclose (f);
1244 }
1245
1246
1247
1248
1249
1250
1251 void
1252 save_file_position (const vfs_path_t *filename_vpath, long line, long column, off_t offset,
1253 GArray *bookmarks)
1254 {
1255 static size_t filepos_max_saved_entries = 0;
1256 char *fn, *tmp_fn;
1257 FILE *f, *tmp_f;
1258 char buf[MC_MAXPATHLEN + 100];
1259 size_t i;
1260 const size_t len = vfs_path_len (filename_vpath);
1261 gboolean src_error = FALSE;
1262
1263 if (filepos_max_saved_entries == 0)
1264 filepos_max_saved_entries = mc_config_get_int (mc_global.main_config, CONFIG_APP_SECTION,
1265 "filepos_max_saved_entries", 1024);
1266
1267 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1268 if (fn == NULL)
1269 goto early_error;
1270
1271 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
1272
1273
1274 f = fopen (fn, "w");
1275 if (f == NULL)
1276 goto open_target_error;
1277
1278 tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
1279 tmp_f = fopen (tmp_fn, "r");
1280 if (tmp_f == NULL)
1281 {
1282 src_error = TRUE;
1283 goto open_source_error;
1284 }
1285
1286
1287 if (line != 1 || column != 0 || bookmarks != NULL)
1288 {
1289 if (fprintf
1290 (f, "%s %ld;%ld;%" PRIuMAX, vfs_path_as_str (filename_vpath), line, column,
1291 (uintmax_t) offset) < 0)
1292 goto write_position_error;
1293 if (bookmarks != NULL)
1294 for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
1295 if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
1296 goto write_position_error;
1297
1298 if (fprintf (f, "\n") < 0)
1299 goto write_position_error;
1300 }
1301
1302 i = 1;
1303 while (fgets (buf, sizeof (buf), tmp_f) != NULL)
1304 {
1305 if (buf[len] == ' ' && strncmp (buf, vfs_path_as_str (filename_vpath), len) == 0
1306 && strchr (&buf[len + 1], ' ') == NULL)
1307 continue;
1308
1309 fprintf (f, "%s", buf);
1310 if (++i > filepos_max_saved_entries)
1311 break;
1312 }
1313
1314 write_position_error:
1315 fclose (tmp_f);
1316 open_source_error:
1317 g_free (tmp_fn);
1318 fclose (f);
1319 if (src_error)
1320 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
1321 else
1322 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
1323 open_target_error:
1324 g_free (fn);
1325 early_error:
1326 if (bookmarks != NULL)
1327 g_array_free (bookmarks, TRUE);
1328 }
1329
1330
1331
1332 extern int
1333 ascii_alpha_to_cntrl (int ch)
1334 {
1335 if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
1336 ch &= 0x1f;
1337
1338 return ch;
1339 }
1340
1341
1342
1343 const char *
1344 Q_ (const char *s)
1345 {
1346 const char *result, *sep;
1347
1348 result = _(s);
1349 sep = strchr (result, '|');
1350
1351 return sep != NULL ? sep + 1 : result;
1352 }
1353
1354
1355
1356 gboolean
1357 mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
1358 {
1359 struct stat stat_buf;
1360 char *backup_path;
1361 gboolean ret;
1362
1363 if (!exist_file (file_name))
1364 return FALSE;
1365
1366 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1367 if (backup_path == NULL)
1368 return FALSE;
1369
1370 ret = mc_util_write_backup_content (file_name, backup_path);
1371 if (ret)
1372 {
1373
1374 if (stat (file_name, &stat_buf) == 0)
1375 chmod (backup_path, stat_buf.st_mode);
1376 else
1377 chmod (backup_path, S_IRUSR | S_IWUSR);
1378 }
1379
1380 g_free (backup_path);
1381
1382 return ret;
1383 }
1384
1385
1386
1387 gboolean
1388 mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
1389 {
1390 gboolean ret;
1391 char *backup_path;
1392
1393 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1394 if (backup_path == NULL)
1395 return FALSE;
1396
1397 ret = mc_util_write_backup_content (backup_path, file_name);
1398 g_free (backup_path);
1399
1400 return ret;
1401 }
1402
1403
1404
1405 gboolean
1406 mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
1407 {
1408 char *backup_path;
1409
1410 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1411 if (backup_path == NULL)
1412 return FALSE;
1413
1414 if (exist_file (backup_path))
1415 {
1416 vfs_path_t *vpath;
1417
1418 vpath = vfs_path_from_str (backup_path);
1419 mc_unlink (vpath);
1420 vfs_path_free (vpath, TRUE);
1421 }
1422
1423 g_free (backup_path);
1424 return TRUE;
1425 }
1426
1427
1428
1429
1430
1431
1432
1433 char *
1434 guess_message_value (void)
1435 {
1436 static const char *const var[] = {
1437
1438
1439 "LC_ALL",
1440
1441 "LC_MESSAGES",
1442
1443 "LANG",
1444
1445 NULL
1446 };
1447
1448 size_t i;
1449 const char *locale = NULL;
1450
1451 for (i = 0; var[i] != NULL; i++)
1452 {
1453 locale = getenv (var[i]);
1454 if (locale != NULL && locale[0] != '\0')
1455 break;
1456 }
1457
1458 if (locale == NULL)
1459 locale = "";
1460
1461 return g_strdup (locale);
1462 }
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473 const char *
1474 mc_get_profile_root (void)
1475 {
1476 static const char *profile_root = NULL;
1477
1478 if (profile_root == NULL)
1479 {
1480 profile_root = g_getenv ("MC_PROFILE_ROOT");
1481 if (profile_root == NULL || *profile_root == '\0')
1482 profile_root = mc_config_get_home_dir ();
1483 }
1484
1485 return profile_root;
1486 }
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498 void
1499 mc_propagate_error (GError **dest, int code, const char *format, ...)
1500 {
1501 if (dest != NULL && *dest == NULL)
1502 {
1503 GError *tmp_error;
1504 va_list args;
1505
1506 va_start (args, format);
1507 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1508 va_end (args);
1509
1510 g_propagate_error (dest, tmp_error);
1511 }
1512 }
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524 void
1525 mc_replace_error (GError **dest, int code, const char *format, ...)
1526 {
1527 if (dest != NULL)
1528 {
1529 GError *tmp_error;
1530 va_list args;
1531
1532 va_start (args, format);
1533 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1534 va_end (args);
1535
1536 g_error_free (*dest);
1537 *dest = NULL;
1538 g_propagate_error (dest, tmp_error);
1539 }
1540 }
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553 gboolean
1554 mc_time_elapsed (gint64 *timestamp, gint64 delay)
1555 {
1556 gint64 now;
1557
1558 now = g_get_monotonic_time ();
1559
1560 if (now >= *timestamp && now < *timestamp + delay)
1561 return FALSE;
1562
1563 *timestamp = now;
1564 return TRUE;
1565 }
1566
1567