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