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