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;
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 while (fgets (buf, sizeof (buf), f) != NULL)
1005 {
1006 const char *p;
1007 gchar **pos_tokens;
1008
1009
1010 if (strncmp (buf, vfs_path_as_str (filename_vpath), len) != 0)
1011 continue;
1012
1013
1014 if (buf[len] != ' ')
1015 continue;
1016
1017
1018 p = &buf[len + 1];
1019 if (strchr (p, ' ') != NULL)
1020 continue;
1021
1022 pos_tokens = g_strsplit (p, ";", 3 + MAX_SAVED_BOOKMARKS);
1023 if (pos_tokens[0] == NULL)
1024 {
1025 *line = 1;
1026 *column = 0;
1027 *offset = 0;
1028 }
1029 else
1030 {
1031 *line = strtol (pos_tokens[0], NULL, 10);
1032 if (pos_tokens[1] == NULL)
1033 {
1034 *column = 0;
1035 *offset = 0;
1036 }
1037 else
1038 {
1039 *column = strtol (pos_tokens[1], NULL, 10);
1040 if (pos_tokens[2] == NULL)
1041 *offset = 0;
1042 else if (bookmarks != NULL)
1043 {
1044 size_t i;
1045
1046 *offset = (off_t) g_ascii_strtoll (pos_tokens[2], NULL, 10);
1047
1048 for (i = 0; i < MAX_SAVED_BOOKMARKS && pos_tokens[3 + i] != NULL; i++)
1049 {
1050 size_t val;
1051
1052 val = strtoul (pos_tokens[3 + i], NULL, 10);
1053 g_array_append_val (*bookmarks, val);
1054 }
1055 }
1056 }
1057 }
1058
1059 g_strfreev (pos_tokens);
1060 }
1061
1062 fclose (f);
1063 }
1064
1065
1066
1067
1068
1069
1070 void
1071 save_file_position (const vfs_path_t *filename_vpath, long line, long column, off_t offset,
1072 GArray *bookmarks)
1073 {
1074 static size_t filepos_max_saved_entries = 0;
1075 char *fn, *tmp_fn;
1076 FILE *f, *tmp_f;
1077 char buf[MC_MAXPATHLEN + 100];
1078 size_t i;
1079 const size_t len = vfs_path_len (filename_vpath);
1080 gboolean src_error = FALSE;
1081
1082 if (filepos_max_saved_entries == 0)
1083 filepos_max_saved_entries = mc_config_get_int (mc_global.main_config, CONFIG_APP_SECTION,
1084 "filepos_max_saved_entries", 1024);
1085
1086 fn = mc_config_get_full_path (MC_FILEPOS_FILE);
1087 if (fn == NULL)
1088 goto early_error;
1089
1090 mc_util_make_backup_if_possible (fn, TMP_SUFFIX);
1091
1092
1093 f = fopen (fn, "w");
1094 if (f == NULL)
1095 goto open_target_error;
1096
1097 tmp_fn = g_strdup_printf ("%s" TMP_SUFFIX, fn);
1098 tmp_f = fopen (tmp_fn, "r");
1099 if (tmp_f == NULL)
1100 {
1101 src_error = TRUE;
1102 goto open_source_error;
1103 }
1104
1105
1106 if (line != 1 || column != 0 || bookmarks != NULL)
1107 {
1108 if (fprintf (f, "%s %ld;%ld;%" PRIuMAX, vfs_path_as_str (filename_vpath), line, column,
1109 (uintmax_t) offset)
1110 < 0)
1111 goto write_position_error;
1112 if (bookmarks != NULL)
1113 for (i = 0; i < bookmarks->len && i < MAX_SAVED_BOOKMARKS; i++)
1114 if (fprintf (f, ";%zu", g_array_index (bookmarks, size_t, i)) < 0)
1115 goto write_position_error;
1116
1117 if (fprintf (f, "\n") < 0)
1118 goto write_position_error;
1119 }
1120
1121 i = 1;
1122 while (fgets (buf, sizeof (buf), tmp_f) != NULL)
1123 {
1124 if (buf[len] == ' ' && strncmp (buf, vfs_path_as_str (filename_vpath), len) == 0
1125 && strchr (&buf[len + 1], ' ') == NULL)
1126 continue;
1127
1128 fprintf (f, "%s", buf);
1129 if (++i > filepos_max_saved_entries)
1130 break;
1131 }
1132
1133 write_position_error:
1134 fclose (tmp_f);
1135 open_source_error:
1136 g_free (tmp_fn);
1137 fclose (f);
1138 if (src_error)
1139 mc_util_restore_from_backup_if_possible (fn, TMP_SUFFIX);
1140 else
1141 mc_util_unlink_backup_if_possible (fn, TMP_SUFFIX);
1142 open_target_error:
1143 g_free (fn);
1144 early_error:
1145 if (bookmarks != NULL)
1146 g_array_free (bookmarks, TRUE);
1147 }
1148
1149
1150
1151 extern int
1152 ascii_alpha_to_cntrl (int ch)
1153 {
1154 if ((ch >= ASCII_A && ch <= ASCII_Z) || (ch >= ASCII_a && ch <= ASCII_z))
1155 ch &= 0x1f;
1156
1157 return ch;
1158 }
1159
1160
1161
1162 const char *
1163 Q_ (const char *s)
1164 {
1165 const char *result, *sep;
1166
1167 result = _ (s);
1168 sep = strchr (result, '|');
1169
1170 return sep != NULL ? sep + 1 : result;
1171 }
1172
1173
1174
1175 gboolean
1176 mc_util_make_backup_if_possible (const char *file_name, const char *backup_suffix)
1177 {
1178 struct stat stat_buf;
1179 char *backup_path;
1180 gboolean ret;
1181
1182 if (!exist_file (file_name))
1183 return FALSE;
1184
1185 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1186 if (backup_path == NULL)
1187 return FALSE;
1188
1189 ret = mc_util_write_backup_content (file_name, backup_path);
1190 if (ret)
1191 {
1192
1193 if (stat (file_name, &stat_buf) == 0)
1194 chmod (backup_path, stat_buf.st_mode);
1195 else
1196 chmod (backup_path, S_IRUSR | S_IWUSR);
1197 }
1198
1199 g_free (backup_path);
1200
1201 return ret;
1202 }
1203
1204
1205
1206 gboolean
1207 mc_util_restore_from_backup_if_possible (const char *file_name, const char *backup_suffix)
1208 {
1209 gboolean ret;
1210 char *backup_path;
1211
1212 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1213 if (backup_path == NULL)
1214 return FALSE;
1215
1216 ret = mc_util_write_backup_content (backup_path, file_name);
1217 g_free (backup_path);
1218
1219 return ret;
1220 }
1221
1222
1223
1224 gboolean
1225 mc_util_unlink_backup_if_possible (const char *file_name, const char *backup_suffix)
1226 {
1227 char *backup_path;
1228
1229 backup_path = g_strdup_printf ("%s%s", file_name, backup_suffix);
1230 if (backup_path == NULL)
1231 return FALSE;
1232
1233 if (exist_file (backup_path))
1234 {
1235 vfs_path_t *vpath;
1236
1237 vpath = vfs_path_from_str (backup_path);
1238 mc_unlink (vpath);
1239 vfs_path_free (vpath, TRUE);
1240 }
1241
1242 g_free (backup_path);
1243 return TRUE;
1244 }
1245
1246
1247
1248
1249
1250
1251
1252 char *
1253 guess_message_value (void)
1254 {
1255 static const char *const var[] = {
1256
1257
1258 "LC_ALL",
1259
1260 "LC_MESSAGES",
1261
1262 "LANG",
1263
1264 NULL
1265 };
1266
1267 size_t i;
1268 const char *locale = NULL;
1269
1270 for (i = 0; var[i] != NULL; i++)
1271 {
1272 locale = getenv (var[i]);
1273 if (locale != NULL && locale[0] != '\0')
1274 break;
1275 }
1276
1277 if (locale == NULL)
1278 locale = "";
1279
1280 return g_strdup (locale);
1281 }
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292 const char *
1293 mc_get_profile_root (void)
1294 {
1295 static const char *profile_root = NULL;
1296
1297 if (profile_root == NULL)
1298 {
1299 profile_root = g_getenv ("MC_PROFILE_ROOT");
1300 if (profile_root == NULL || *profile_root == '\0')
1301 profile_root = mc_config_get_home_dir ();
1302 }
1303
1304 return profile_root;
1305 }
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317 void
1318 mc_propagate_error (GError **dest, int code, const char *format, ...)
1319 {
1320 if (dest != NULL && *dest == NULL)
1321 {
1322 GError *tmp_error;
1323 va_list args;
1324
1325 va_start (args, format);
1326 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1327 va_end (args);
1328
1329 g_propagate_error (dest, tmp_error);
1330 }
1331 }
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343 void
1344 mc_replace_error (GError **dest, int code, const char *format, ...)
1345 {
1346 if (dest != NULL)
1347 {
1348 GError *tmp_error;
1349 va_list args;
1350
1351 va_start (args, format);
1352 tmp_error = g_error_new_valist (MC_ERROR, code, format, args);
1353 va_end (args);
1354
1355 g_error_free (*dest);
1356 *dest = NULL;
1357 g_propagate_error (dest, tmp_error);
1358 }
1359 }
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372 gboolean
1373 mc_time_elapsed (gint64 *timestamp, gint64 delay)
1374 {
1375 gint64 now;
1376
1377 now = g_get_monotonic_time ();
1378
1379 if (now >= *timestamp && now < *timestamp + delay)
1380 return FALSE;
1381
1382 *timestamp = now;
1383 return TRUE;
1384 }
1385
1386