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