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