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