First bunch of mhl_mem_free removal patches
[midnight-commander.git] / vfs / utilvfs.c
blob08cb3dd804dc797e92806491ddc1d7b5642eb615
1 /* Utilities for VFS modules.
3 Copyright (C) 1988, 1992, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007 Free Software Foundation, Inc.
5 Copyright (C) 1995, 1996 Miguel de Icaza
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License
9 as published by the Free Software Foundation; either version 2 of
10 the License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21 #include <config.h>
23 #include <ctype.h>
25 #include <mhl/types.h>
26 #include <mhl/memory.h>
27 #include <mhl/string.h>
29 #include "../src/global.h"
30 #include "../src/tty.h" /* enable/disable interrupt key */
31 #include "../src/wtools.h" /* message() */
32 #include "../src/main.h" /* print_vfs_message */
33 #include "utilvfs.h"
34 #include "vfs.h"
35 #include "../src/unixcompat.h"
36 #include "../src/history.h"
38 /* Extract the hostname and username from the path */
39 /* path is in the form: [user@]hostname:port/remote-dir, e.g.:
41 * ftp://sunsite.unc.edu/pub/linux
42 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
43 * ftp://tsx-11.mit.edu:8192/
44 * ftp://joe@foo.edu:11321/private
45 * ftp://joe:password@foo.se
47 * Returns g_malloc()ed host, user and pass they are present.
48 * If the user is empty, e.g. ftp://@roxanne/private, and URL_ALLOW_ANON
49 * is not set, then the current login name is supplied.
51 * Return value is a g_malloc()ed string with the pathname relative to the
52 * host.
55 #ifdef USE_NETCODE
56 char *
57 vfs_split_url (const char *path, char **host, char **user, int *port,
58 char **pass, int default_port, int flags)
60 struct passwd *passwd_info;
61 char *dir, *colon, *inner_colon, *at, *rest;
62 char *retval;
63 char * const pcopy = mhl_str_dup (path);
64 const char *pend = pcopy + strlen (pcopy);
66 if (pass)
67 *pass = NULL;
68 *port = default_port;
69 *user = NULL;
70 retval = NULL;
72 dir = pcopy;
73 if (!(flags & URL_NOSLASH)) {
74 /* locate path component */
75 while (*dir != PATH_SEP && *dir)
76 dir++;
77 if (*dir) {
78 retval = mhl_str_dup (dir);
79 *dir = 0;
80 } else
81 retval = mhl_str_dup (PATH_SEP_STR);
84 /* search for any possible user */
85 at = strrchr (pcopy, '@');
87 /* We have a username */
88 if (at) {
89 *at = 0;
90 inner_colon = strchr (pcopy, ':');
91 if (inner_colon) {
92 *inner_colon = 0;
93 inner_colon++;
94 if (pass)
95 *pass = mhl_str_dup (inner_colon);
97 if (*pcopy != 0)
98 *user = mhl_str_dup (pcopy);
100 if (pend == at + 1)
101 rest = at;
102 else
103 rest = at + 1;
104 } else
105 rest = pcopy;
107 if (!*user && !(flags & URL_ALLOW_ANON)) {
108 passwd_info = getpwuid (geteuid ());
109 if (passwd_info && passwd_info->pw_name)
110 *user = mhl_str_dup (passwd_info->pw_name);
111 else {
112 /* This is very unlikely to happen */
113 *user = mhl_str_dup ("anonymous");
115 endpwent ();
118 /* Check if the host comes with a port spec, if so, chop it */
119 colon = strchr (rest, ':');
120 if (colon) {
121 *colon = 0;
122 if (sscanf (colon + 1, "%d", port) == 1) {
123 if (*port <= 0 || *port >= 65536)
124 *port = default_port;
125 } else {
126 while (*(++colon)) {
127 switch (*colon) {
128 case 'C':
129 *port = 1;
130 break;
131 case 'r':
132 *port = 2;
133 break;
138 if (host)
139 *host = mhl_str_dup (rest);
141 g_free (pcopy);
142 return retval;
144 #endif /* USE_NETCODE */
147 * Look up a user or group name from a uid/gid, maintaining a cache.
148 * FIXME, for now it's a one-entry cache.
149 * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
150 * This file should be modified for non-unix systems to do something
151 * reasonable.
154 #ifndef TUNMLEN
155 #define TUNMLEN 256
156 #endif
157 #ifndef TGNMLEN
158 #define TGNMLEN 256
159 #endif
161 #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
162 #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
165 vfs_finduid (const char *uname)
167 static int saveuid = -993;
168 static char saveuname[TUNMLEN];
169 static int my_uid = -993;
171 struct passwd *pw;
173 if (uname[0] != saveuname[0] /* Quick test w/o proc call */
174 ||0 != strncmp (uname, saveuname, TUNMLEN)) {
175 g_strlcpy (saveuname, uname, TUNMLEN);
176 pw = getpwnam (uname);
177 if (pw) {
178 saveuid = pw->pw_uid;
179 } else {
180 saveuid = myuid;
183 return saveuid;
187 vfs_findgid (const char *gname)
189 static int savegid = -993;
190 static char savegname[TGNMLEN];
191 static int my_gid = -993;
193 struct group *gr;
195 if (gname[0] != savegname[0] /* Quick test w/o proc call */
196 ||0 != strncmp (gname, savegname, TUNMLEN)) {
197 g_strlcpy (savegname, gname, TUNMLEN);
198 gr = getgrnam (gname);
199 if (gr) {
200 savegid = gr->gr_gid;
201 } else {
202 savegid = mygid;
205 return savegid;
209 * Create a temporary file with a name resembling the original.
210 * This is needed e.g. for local copies requested by extfs.
211 * Some extfs scripts may look at the extension.
212 * We also protect stupid scripts agains dangerous names.
215 vfs_mkstemps (char **pname, const char *prefix, const char *basename)
217 const char *p;
218 char *suffix, *q;
219 int shift;
220 int fd;
222 /* Strip directories */
223 p = strrchr (basename, PATH_SEP);
224 if (!p)
225 p = basename;
226 else
227 p++;
229 /* Protection against very long names */
230 shift = strlen (p) - (MC_MAXPATHLEN - 16);
231 if (shift > 0)
232 p += shift;
234 suffix = g_malloc (MC_MAXPATHLEN);
236 /* Protection against unusual characters */
237 q = suffix;
238 while (*p && (*p != '#')) {
239 if (strchr (".-_@", *p) || isalnum ((unsigned char) *p))
240 *q++ = *p;
241 p++;
243 *q = 0;
245 fd = mc_mkstemps (pname, prefix, suffix);
246 g_free (suffix);
247 return fd;
250 /* Parsing code is used by ftpfs, fish and extfs */
251 #define MAXCOLS 30
253 static char *columns[MAXCOLS]; /* Points to the string in column n */
254 static int column_ptr[MAXCOLS]; /* Index from 0 to the starting positions of the columns */
257 vfs_split_text (char *p)
259 char *original = p;
260 int numcols;
262 memset (columns, 0, sizeof (columns));
264 for (numcols = 0; *p && numcols < MAXCOLS; numcols++) {
265 while (*p == ' ' || *p == '\r' || *p == '\n') {
266 *p = 0;
267 p++;
269 columns[numcols] = p;
270 column_ptr[numcols] = p - original;
271 while (*p && *p != ' ' && *p != '\r' && *p != '\n')
272 p++;
274 return numcols;
277 static int
278 is_num (int idx)
280 char *column = columns[idx];
282 if (!column || column[0] < '0' || column[0] > '9')
283 return 0;
285 return 1;
288 /* Return 1 for MM-DD-YY and MM-DD-YYYY */
289 static int
290 is_dos_date (const char *str)
292 int len;
294 if (!str)
295 return 0;
297 len = strlen (str);
298 if (len != 8 && len != 10)
299 return 0;
301 if (str[2] != str[5])
302 return 0;
304 if (!strchr ("\\-/", (int) str[2]))
305 return 0;
307 return 1;
310 static int
311 is_week (const char *str, struct tm *tim)
313 static const char *week = "SunMonTueWedThuFriSat";
314 const char *pos;
316 if (!str)
317 return 0;
319 if ((pos = strstr (week, str)) != NULL) {
320 if (tim != NULL)
321 tim->tm_wday = (pos - week) / 3;
322 return 1;
324 return 0;
327 static int
328 is_month (const char *str, struct tm *tim)
330 static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
331 const char *pos;
333 if (!str)
334 return 0;
336 if ((pos = strstr (month, str)) != NULL) {
337 if (tim != NULL)
338 tim->tm_mon = (pos - month) / 3;
339 return 1;
341 return 0;
345 * Check for possible locale's abbreviated month name (Jan..Dec).
346 * Any 3 bytes long string without digit, control and punctuation characters.
347 * isalpha() is locale specific, so it cannot be used if current
348 * locale is "C" and ftp server use Cyrillic.
349 * NB: It is assumed there are no whitespaces in month.
351 static int
352 is_localized_month (const char *month)
354 int i = 0;
356 if (!month)
357 return 0;
359 while ((i < 3) && *month && !isdigit ((unsigned char) *month)
360 && !iscntrl ((unsigned char) *month)
361 && !ispunct ((unsigned char) *month)) {
362 i++;
363 month++;
365 return ((i == 3) && (*month == 0));
368 static int
369 is_time (const char *str, struct tm *tim)
371 const char *p, *p2;
373 if (!str)
374 return 0;
376 if ((p = strchr (str, ':')) && (p2 = strrchr (str, ':'))) {
377 if (p != p2) {
378 if (sscanf
379 (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min,
380 &tim->tm_sec) != 3)
381 return 0;
382 } else {
383 if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
384 return 0;
386 } else
387 return 0;
389 return 1;
392 static int
393 is_year (char *str, struct tm *tim)
395 long year;
397 if (!str)
398 return 0;
400 if (strchr (str, ':'))
401 return 0;
403 if (strlen (str) != 4)
404 return 0;
406 if (sscanf (str, "%ld", &year) != 1)
407 return 0;
409 if (year < 1900 || year > 3000)
410 return 0;
412 tim->tm_year = (int) (year - 1900);
414 return 1;
417 bool
418 vfs_parse_filetype (const char *s, size_t *ret_skipped, mode_t *ret_type)
420 mode_t type;
422 switch (*s) {
423 case 'd': type = S_IFDIR; break;
424 case 'b': type = S_IFBLK; break;
425 case 'c': type = S_IFCHR; break;
426 case 'l': type = S_IFLNK; break;
427 #ifdef S_IFSOCK
428 case 's': type = S_IFSOCK; break;
429 #else
430 case 's': type = S_IFIFO; break;
431 #endif
432 #ifdef S_IFDOOR /* Solaris door */
433 case 'D': type = S_IFDOOR; break;
434 #else
435 case 'D': type = S_IFIFO; break;
436 #endif
437 case 'p': type = S_IFIFO; break;
438 #ifdef S_IFNAM /* Special named files */
439 case 'n': type = S_IFNAM; break;
440 #else
441 case 'n': type = S_IFREG; break;
442 #endif
443 case 'm': /* Don't know what these are :-) */
444 case '-':
445 case '?': type = S_IFREG; break;
446 default: return FALSE;
449 *ret_type = type;
450 *ret_skipped = 1;
451 return TRUE;
454 bool
455 vfs_parse_fileperms (const char *s, size_t *ret_skipped, mode_t *ret_perms)
457 const char *p;
458 mode_t perms;
460 p = s;
461 perms = 0;
463 switch (*p++) {
464 case '-': break;
465 case 'r': perms |= S_IRUSR; break;
466 default: return FALSE;
468 switch (*p++) {
469 case '-': break;
470 case 'w': perms |= S_IWUSR; break;
471 default: return FALSE;
473 switch (*p++) {
474 case '-': break;
475 case 'S': perms |= S_ISUID; break;
476 case 's': perms |= S_IXUSR | S_ISUID; break;
477 case 'x': perms |= S_IXUSR; break;
478 default: return FALSE;
480 switch (*p++) {
481 case '-': break;
482 case 'r': perms |= S_IRGRP; break;
483 default: return FALSE;
485 switch (*p++) {
486 case '-': break;
487 case 'w': perms |= S_IWGRP; break;
488 default: return FALSE;
490 switch (*p++) {
491 case '-': break;
492 case 'S': perms |= S_ISGID; break;
493 case 'l': perms |= S_ISGID; break; /* found on Solaris */
494 case 's': perms |= S_IXGRP | S_ISGID; break;
495 case 'x': perms |= S_IXGRP; break;
496 default: return FALSE;
498 switch (*p++) {
499 case '-': break;
500 case 'r': perms |= S_IROTH; break;
501 default: return FALSE;
503 switch (*p++) {
504 case '-': break;
505 case 'w': perms |= S_IWOTH; break;
506 default: return FALSE;
508 switch (*p++) {
509 case '-': break;
510 case 'T': perms |= S_ISVTX; break;
511 case 't': perms |= S_IXOTH | S_ISVTX; break;
512 case 'x': perms |= S_IXOTH; break;
513 default: return FALSE;
515 if (*p == '+') { /* ACLs on Solaris, HP-UX and others */
516 p++;
519 *ret_skipped = p - s;
520 *ret_perms = perms;
521 return TRUE;
524 bool
525 vfs_parse_filemode (const char *s, size_t *ret_skipped,
526 mode_t *ret_mode)
528 const char *p;
529 mode_t type, perms;
530 size_t skipped;
532 p = s;
534 if (!vfs_parse_filetype (p, &skipped, &type))
535 return FALSE;
536 p += skipped;
538 if (!vfs_parse_fileperms (p, &skipped, &perms))
539 return FALSE;
540 p += skipped;
542 *ret_skipped = p - s;
543 *ret_mode = type | perms;
544 return TRUE;
547 bool
548 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped,
549 mode_t *ret_mode)
551 const char *p;
552 mode_t remote_type = 0, local_type, perms = 0;
554 p = s;
556 // isoctal
557 while(*p >= '0' && *p <= '7')
559 perms *= 010;
560 perms += (*p - '0');
561 ++p;
564 if (*p++ != ' ')
565 return FALSE;
567 while(*p >= '0' && *p <= '7')
569 remote_type *= 010;
570 remote_type += (*p - '0');
571 ++p;
574 if (*p++ != ' ')
575 return FALSE;
577 /* generated with:
578 $ perl -e 'use Fcntl ":mode";
579 my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
580 foreach $t (@modes) { printf ("%o\n", $t); };'
581 TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
582 (see vfs_parse_filetype)
585 switch (remote_type)
587 case 020000:
588 local_type = S_IFCHR; break;
589 case 040000:
590 local_type = S_IFDIR; break;
591 case 060000:
592 local_type = S_IFBLK; break;
593 case 0120000:
594 local_type = S_IFLNK; break;
595 case 0100000:
596 default:// don't know what is it
597 local_type = S_IFREG; break;
600 *ret_skipped = p - s;
601 *ret_mode = local_type | perms;
602 return TRUE;
605 /* This function parses from idx in the columns[] array */
607 vfs_parse_filedate (int idx, time_t *t)
609 char *p;
610 struct tm tim;
611 int d[3];
612 int got_year = 0;
613 int l10n = 0; /* Locale's abbreviated month name */
614 time_t current_time;
615 struct tm *local_time;
617 /* Let's setup default time values */
618 current_time = time (NULL);
619 local_time = localtime (&current_time);
620 tim.tm_mday = local_time->tm_mday;
621 tim.tm_mon = local_time->tm_mon;
622 tim.tm_year = local_time->tm_year;
624 tim.tm_hour = 0;
625 tim.tm_min = 0;
626 tim.tm_sec = 0;
627 tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */
629 p = columns[idx++];
631 /* We eat weekday name in case of extfs */
632 if (is_week (p, &tim))
633 p = columns[idx++];
635 /* Month name */
636 if (is_month (p, &tim)) {
637 /* And we expect, it followed by day number */
638 if (is_num (idx))
639 tim.tm_mday = (int) atol (columns[idx++]);
640 else
641 return 0; /* No day */
643 } else {
644 /* We expect:
645 3 fields max or we'll see oddities with certain file names.
646 So both year and time is not allowed.
647 Mon DD hh:mm[:ss]
648 Mon DD YYYY
649 But in case of extfs we allow these date formats:
650 MM-DD-YY hh:mm[:ss]
651 where Mon is Jan-Dec, DD, MM, YY two digit day, month, year,
652 YYYY four digit year, hh, mm, ss two digit hour, minute or second. */
654 /* Special case with MM-DD-YY or MM-DD-YYYY */
655 if (is_dos_date (p)) {
656 p[2] = p[5] = '-';
658 if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) == 3) {
659 /* Months are zero based */
660 if (d[0] > 0)
661 d[0]--;
663 if (d[2] > 1900) {
664 d[2] -= 1900;
665 } else {
666 /* Y2K madness */
667 if (d[2] < 70)
668 d[2] += 100;
671 tim.tm_mon = d[0];
672 tim.tm_mday = d[1];
673 tim.tm_year = d[2];
674 got_year = 1;
675 } else
676 return 0; /* sscanf failed */
677 } else {
678 /* Locale's abbreviated month name followed by day number */
679 if (is_localized_month (p) && (is_num (idx++)))
680 l10n = 1;
681 else
682 return 0; /* unsupported format */
686 /* Here we expect to find time or year */
687 if (is_num (idx) && (is_time (columns[idx], &tim)
688 || (got_year = is_year (columns[idx], &tim))))
689 idx++;
690 else
691 return 0; /* Neither time nor date */
694 * If the date is less than 6 months in the past, it is shown without year
695 * other dates in the past or future are shown with year but without time
696 * This does not check for years before 1900 ... I don't know, how
697 * to represent them at all
699 if (!got_year && local_time->tm_mon < 6
700 && local_time->tm_mon < tim.tm_mon
701 && tim.tm_mon - local_time->tm_mon >= 6)
703 tim.tm_year--;
705 if (l10n || (*t = mktime (&tim)) < 0)
706 *t = 0;
707 return idx;
711 vfs_parse_ls_lga (const char *p, struct stat *s, char **filename,
712 char **linkname)
714 int idx, idx2, num_cols;
715 int i;
716 char *p_copy = NULL;
717 char *t = NULL;
718 const char *line = p;
719 size_t skipped;
721 if (strncmp (p, "total", 5) == 0)
722 return 0;
724 if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
725 goto error;
726 p += skipped;
728 if (*p == ' ') /* Notwell 4 */
729 p++;
730 if (*p == '[') {
731 if (strlen (p) <= 8 || p[8] != ']')
732 goto error;
733 /* Should parse here the Notwell permissions :) */
734 if (S_ISDIR (s->st_mode))
735 s->st_mode |=
736 (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP
737 | S_IXOTH);
738 else
739 s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
740 p += 9;
741 } else {
742 size_t skipped;
743 mode_t perms;
745 if (!vfs_parse_fileperms (p, &skipped, &perms))
746 goto error;
747 p += skipped;
748 s->st_mode |= perms;
751 p_copy = mhl_str_dup (p);
752 num_cols = vfs_split_text (p_copy);
754 s->st_nlink = atol (columns[0]);
755 if (s->st_nlink <= 0)
756 goto error;
758 if (!is_num (1))
759 s->st_uid = vfs_finduid (columns[1]);
760 else
761 s->st_uid = (uid_t) atol (columns[1]);
763 /* Mhm, the ls -lg did not produce a group field */
764 for (idx = 3; idx <= 5; idx++)
765 if (is_month (columns[idx], NULL) || is_week (columns[idx], NULL)
766 || is_dos_date (columns[idx])
767 || is_localized_month (columns[idx]))
768 break;
770 if (idx == 6
771 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
772 goto error;
774 /* We don't have gid */
775 if (idx == 3
776 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
777 idx2 = 2;
778 else {
779 /* We have gid field */
780 if (is_num (2))
781 s->st_gid = (gid_t) atol (columns[2]);
782 else
783 s->st_gid = vfs_findgid (columns[2]);
784 idx2 = 3;
787 /* This is device */
788 if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode)) {
789 int maj, min;
791 /* Corner case: there is no whitespace(s) between maj & min */
792 if (!is_num (idx2) && idx2 == 2) {
793 if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &min, &min) != 2)
794 goto error;
795 } else {
796 if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
797 goto error;
799 if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
800 goto error;
802 #ifdef HAVE_STRUCT_STAT_ST_RDEV
803 s->st_rdev = makedev (maj, min);
804 #endif
805 s->st_size = 0;
807 } else {
808 /* Common file size */
809 if (!is_num (idx2))
810 goto error;
812 #ifdef HAVE_ATOLL
813 s->st_size = (off_t) atoll (columns[idx2]);
814 #else
815 s->st_size = (off_t) atof (columns[idx2]);
816 #endif
817 #ifdef HAVE_STRUCT_STAT_ST_RDEV
818 s->st_rdev = 0;
819 #endif
822 idx = vfs_parse_filedate (idx, &s->st_mtime);
823 if (!idx)
824 goto error;
825 /* Use resulting time value */
826 s->st_atime = s->st_ctime = s->st_mtime;
827 /* s->st_dev and s->st_ino must be initialized by vfs_s_new_inode () */
828 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
829 s->st_blksize = 512;
830 #endif
831 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
832 s->st_blocks = (s->st_size + 511) / 512;
833 #endif
835 for (i = idx + 1, idx2 = 0; i < num_cols; i++)
836 if (strcmp (columns[i], "->") == 0) {
837 idx2 = i;
838 break;
841 if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1))) /* Maybe a hardlink? (in extfs) */
842 &&idx2) {
844 if (filename) {
845 *filename =
846 g_strndup (p + column_ptr[idx],
847 column_ptr[idx2] - column_ptr[idx] - 1);
849 if (linkname) {
850 t = mhl_str_dup (p + column_ptr[idx2 + 1]);
851 *linkname = t;
853 } else {
854 /* Extract the filename from the string copy, not from the columns
855 * this way we have a chance of entering hidden directories like ". ."
857 if (filename) {
859 * filename = mhl_str_dup (columns [idx++]);
862 t = mhl_str_dup (p + column_ptr[idx]);
863 *filename = t;
865 if (linkname)
866 *linkname = NULL;
869 if (t) {
870 int p = strlen (t);
871 if ((--p > 0) && (t[p] == '\r' || t[p] == '\n'))
872 t[p] = 0;
873 if ((--p > 0) && (t[p] == '\r' || t[p] == '\n'))
874 t[p] = 0;
877 g_free (p_copy);
878 return 1;
880 error:
882 static int errorcount = 0;
884 if (++errorcount < 5) {
885 message (D_ERROR, _("Cannot parse:"), "%s",
886 (p_copy && *p_copy) ? p_copy : line);
887 } else if (errorcount == 5)
888 message (D_ERROR, MSG_ERROR,
889 _("More parsing errors will be ignored."));
892 g_free (p_copy);
893 return 0;
896 void
897 vfs_die (const char *m)
899 message (D_ERROR, _("Internal error:"), "%s", m);
900 exit (1);
903 char *
904 vfs_get_password (const char *msg)
906 return input_dialog (msg, _("Password:"), MC_HISTORY_VFS_PASSWORD, INPUT_PASSWORD);